Skip to main content
ALPHA    This is new software undergoing tests! Thank you for your patience.

Candidate: Paul Honey honeyp Assessed by: Nicholas Tollervey ntoll

Python (2023) ~ Grade 1 (Initial)

You're having a laugh!

I would like to design a joke generator, aimed at children, which will tell a joke based on a topic and/or some inputs of the users' choosing.

Attached files
Filename (click to download) Size Uploaded by
Code_grab_1.PNG 24.9 KB honeyp
Markdown code
![Code_grab_1.PNG](/media/assessment/7362c701/2022-12-03/07-09-52/Code_grab_1.PNG "Code_grab_1.PNG")
Code_grab_1.PNG 24.9 KB honeyp
Markdown code
![Code_grab_1.PNG](/media/assessment/7362c701/2022-12-03/07-10-06/Code_grab_1.PNG "Code_grab_1.PNG")
Code_grab_2.PNG 56.1 KB honeyp
Markdown code
![Code_grab_2.PNG](/media/assessment/7362c701/2022-12-03/08-15-45/Code_grab_2.PNG "Code_grab_2.PNG")
Aliens_and_squares.py 1.1 KB honeyp
Markdown code
```Python
from pygame.transform import flip
alien = Actor('alien', topleft=(20, 30))                             # Load alien sprites
alien2 = Actor('alien', topright=(880, 30))
alien3 = Actor('alien', bottomleft=(20, 570))
alien4 = Actor('alien', bottomright=(880, 570))

WIDTH = 900                                                          # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

def draw():
    screen.fill((3, 70, 26))                                         # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), 'gold')    # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), 'cyan')
    alien.draw()                                                     # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)


```
Alien_and_box.py 267 bytes honeyp
Markdown code
```Python
alien = Actor("alien", topleft=(20, 30))
WIDTH = 900
HEIGHT = 600

RED = 200, 0, 0
BOX = Rect((450, 60), (50, 100))


def draw():
    screen.fill((3, 70, 26))
    screen.draw.rect(BOX, RED)
    alien.draw()


def update():
    #alien.angle = 45
    alien.angle -= 9


```
Code_grab_3.PNG 9.1 KB honeyp
Markdown code
![Code_grab_3.PNG](/media/assessment/7362c701/2022-12-04/21-21-45/Code_grab_3.PNG "Code_grab_3.PNG")
laugh1.wav 2.3 MB honeyp
Markdown code
[laugh1.wav](/media/assessment/7362c701/2022-12-07/19-00-57/laugh1.wav){target="_blank"}
hahaha.png 19.8 KB honeyp
Markdown code
![hahaha.png](/media/assessment/7362c701/2022-12-07/19-01-38/hahaha.png "hahaha.png")
button_animals.png 6.7 KB honeyp
Markdown code
![button_animals.png](/media/assessment/7362c701/2022-12-07/19-01-39/button_animals.png "button_animals.png")
button_food.png 5.3 KB honeyp
Markdown code
![button_food.png](/media/assessment/7362c701/2022-12-07/19-01-39/button_food.png "button_food.png")
button_reset.png 3.8 KB honeyp
Markdown code
![button_reset.png](/media/assessment/7362c701/2022-12-07/19-01-39/button_reset.png "button_reset.png")
button_silly.png 5.3 KB honeyp
Markdown code
![button_silly.png](/media/assessment/7362c701/2022-12-07/19-01-39/button_silly.png "button_silly.png")
button_school.png 6.1 KB honeyp
Markdown code
![button_school.png](/media/assessment/7362c701/2022-12-07/19-01-39/button_school.png "button_school.png")
Code_grades_emails.eml 1.3 KB honeyp
Markdown code
[Code_grades_emails.eml](/media/assessment/7362c701/2022-12-10/19-38-03/Code_grades_emails.eml){target="_blank"}
bean.png 116.4 KB honeyp
Markdown code
![bean.png](/media/assessment/7362c701/2023-01-03/05-10-28/bean.png "bean.png")
stage.png 210.6 KB honeyp
Markdown code
![stage.png](/media/assessment/7362c701/2023-01-03/05-10-28/stage.png "stage.png")
micstand.png 4.4 KB honeyp
Markdown code
![micstand.png](/media/assessment/7362c701/2023-01-03/05-10-28/micstand.png "micstand.png")
lol.png 135.1 KB honeyp
Markdown code
![lol.png](/media/assessment/7362c701/2023-01-03/05-10-28/lol.png "lol.png")
neon_mic.png 30.8 KB honeyp
Markdown code
![neon_mic.png](/media/assessment/7362c701/2023-01-03/05-10-28/neon_mic.png "neon_mic.png")
rofl.png 15.0 KB honeyp
Markdown code
![rofl.png](/media/assessment/7362c701/2023-01-03/05-10-28/rofl.png "rofl.png")
laugh2.wav 194.0 KB honeyp
Markdown code
[laugh2.wav](/media/assessment/7362c701/2023-01-03/05-11-09/laugh2.wav){target="_blank"}
drum.wav 674.4 KB honeyp
Markdown code
[drum.wav](/media/assessment/7362c701/2023-01-03/05-11-09/drum.wav){target="_blank"}
slow_clap.wav 2.9 MB honeyp
Markdown code
[slow_clap.wav](/media/assessment/7362c701/2023-01-03/05-11-10/slow_clap.wav){target="_blank"}
Paul_Honey_Grade_1_-_Joke_Generator.py 4.4 KB honeyp
Markdown code
```Python
"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

joke = False

"""
Section 1 - Backgrounds, popups and sounds
"""

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 195))
mic = Actor("micstand", center=(430, 375))
comedy = Actor("comedy", center=(450, 70))
laugh_emoji = Actor("laugh_emoji", midright=(880, 280))
laugh_emoji.angle = -30
background_images = [stage, comedy, neon_mic, mic, laugh_emoji]

raspberry = Actor("raspberry", topright=(485, 125))    # Randomly generated images
haha = Actor("haha", center=(400,300))
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [raspberry, haha, bean, lol, rofl]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 2 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 3 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

"""
Section 4 - The code which tells your jokes
"""

def draw():
    [backgrounds.draw() for backgrounds in background_images]
    [joke_categories.draw() for joke_categories in buttons]

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""

```
Rabbit_on_the_Moon_Font.zip 597.8 KB honeyp
Markdown code
[Rabbit_on_the_Moon_Font.zip](/media/assessment/7362c701/2023-01-09/08-36-41/Rabbit_on_the_Moon_Font.zip){target="_blank"}
Joke_Generator_Images.zip 773.2 KB honeyp
Markdown code
[Joke_Generator_Images.zip](/media/assessment/7362c701/2023-01-09/08-36-57/Joke_Generator_Images.zip){target="_blank"}
Joke_Generator_Sounds.zip 5.2 MB honeyp
Markdown code
[Joke_Generator_Sounds.zip](/media/assessment/7362c701/2023-01-09/08-37-18/Joke_Generator_Sounds.zip){target="_blank"}
Joke_Generator_User_Guide.docx 9.0 MB honeyp
Markdown code
[Joke_Generator_User_Guide.docx](/media/assessment/7362c701/2023-01-09/08-37-33/Joke_Generator_User_Guide.docx){target="_blank"}
Joke_Generator_User_Guide.pdf 4.5 MB honeyp
Markdown code
[Joke_Generator_User_Guide.pdf](/media/assessment/7362c701/2023-01-09/08-37-35/Joke_Generator_User_Guide.pdf){target="_blank"}
Email_to_children_1.PNG 90.6 KB honeyp
Markdown code
![Email_to_children_1.PNG](/media/assessment/7362c701/2023-01-09/08-44-37/Email_to_children_1.PNG "Email_to_children_1.PNG")
Email_to_children_2.PNG 95.6 KB honeyp
Markdown code
![Email_to_children_2.PNG](/media/assessment/7362c701/2023-01-09/08-44-42/Email_to_children_2.PNG "Email_to_children_2.PNG")
Paul_Honey_Grade_1_-_Joke_Generator.py 4.4 KB honeyp
Markdown code
```Python
"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

joke = False

"""
Section 1 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 2 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

"""
Section 3 - Backgrounds, popups and sounds
"""

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 195))
mic = Actor("micstand", center=(430, 375))
comedy = Actor("comedy", center=(450, 70))
laugh_emoji = Actor("laugh_emoji", midright=(880, 280))
laugh_emoji.angle = -30
background_images = [stage, comedy, neon_mic, mic, laugh_emoji]

raspberry = Actor("raspberry", topright=(485, 125))    # Randomly generated images
haha = Actor("haha", center=(400,300))
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [raspberry, haha, bean, lol, rofl]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 4 - The code which tells your jokes
"""

def draw():
    [backgrounds.draw() for backgrounds in background_images]
    [joke_categories.draw() for joke_categories in buttons]

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""

```
Joke_Generator_User_Guide.pdf 4.5 MB honeyp
Markdown code
[Joke_Generator_User_Guide.pdf](/media/assessment/7362c701/2023-01-09/23-06-42/Joke_Generator_User_Guide.pdf){target="_blank"}
Joke_Generator_User_Guide.docx 9.0 MB honeyp
Markdown code
[Joke_Generator_User_Guide.docx](/media/assessment/7362c701/2023-01-09/23-06-42/Joke_Generator_User_Guide.docx){target="_blank"}

Status: Closed (results delivered). 96/100 ~ Pass with DISTINCTION (22/01/2023).


honeyp Paul Honey ~ 02 Dec 2022 9 p.m. (updated: 02 Dec 2022 9:01 p.m.)

Getting started

My ten year old son is very quick witted, constantly coming up with new jokes and one liners and wanting to write them down. I'd like to produce a simple joke generator, one which he can contribute to and get some fun from, that will output a joke based on certain inputs.
I have spoken to my son, who thinks it is a good idea, and asked him to think of some jokes while I am away with work. I plan to aim the program at his age group of 9/10/11 year olds.

My initial idea is to maybe have one or more drop down menus where the user picks a category of joke and then perhaps some other descriptors. Once selected they hit a generate button and a joke is selected based on the selected inputs.
Because I want an interactive program I have initially decided to utilise Pygame Zero for my project


honeyp Paul Honey ~ 03 Dec 2022 10:09 a.m. (updated: 03 Dec 2022 10:12 a.m.)

Experimenting

Simple picture and shape placement

Because the program is aimed at children, I'd like to include some fun images/shapes, relevant to the theme, and engaging background colours. At first I have just been playing around with image placement, animation, playing with size and shape of rectangles and colouring the shapes and backgrounds.

Code
alien = Actor('alien', topleft=(20, 30))  #Load alien sprite
WIDTH = 900  # Set window size
HEIGHT = 600

RED = 200, 0, 0  # Set rectangle colour
BOX = Rect((450, 60), (50, 100))  # Set rectangle position and size

def draw():
      screen.fill((3, 70, 26))  # Background colour
      screen.draw.rect(BOX, RED)  # Draw rectangle
      alien.draw()  # Draw alien
Alien and a Box

Code_grab_1.PNG

I don't plan on using the alien sprite in my final program, I am just using it for convenience at the minute as I familiarise myself with placing and manipulating images.

Playing around

I thought it might be fun to have images spinning in the background so I also added the following to the end of the code:

def update():
    alien.angle -= 9  # Updates the position of the alien, in this case spins clockwise at a set speed

Creating an image filled background

I also played around with adding multiple of the same images, changing positions and trying to flip the image at different positions:

Code
from pygame.transform import flip
alien = Actor('alien', topleft=(20, 30))                             # Load alien sprites
alien2 = Actor('alien', topright=(880, 30))
alien3 = Actor('alien', bottomleft=(20, 570))
alien4 = Actor('alien', bottomright=(880, 570))

WIDTH = 900                                                          # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

def draw():
    screen.fill((3, 70, 26))                                         # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (100, 100)), 'gold')    # Draw squares with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (100, 100)), 'cyan')
    alien.draw()                                                     # Draws alien sprites
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)  # Mirrors/flips the alien image
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)
Aliens and Squares

Code_grab_2.PNG

I found a list of callable colours, for the filled squares, from the following link:

https://robocoast.tech/wp-content/uploads/2021/05/PyGame-Zero-Introduction-Booklet.pdf

I had played with just rotating the aliens through a set number of degrees using the following:

def update():
    alien.angle = 45

I tried doing something similar with the squares I'd drawn, however a solution for this was overly complex

Coding justification

I struggled with trying to mirror/flip the alien image. There were a few differing, and sometimes complicated, methods for how to achieve the outcome shown in the above Aliens and Squares image. I went for an adaptation of the solution I found at the following link, presented by user dryabov:

https://github.com/lordmauve/pgzero/issues/3

As I think I understand it, when and image is drawn, it is assigned to a surface. The first line of the code imports the surface flipping (horizontally or vertically) functionality from pygame.transform. Pygame.transform offers functionality for resizing and repositioning surface pixels.

The code screen.blit(flip(alien2._surf, True, False), alien2.topleft) uses the blit command to draw the image alien2 and flips it about the y axis using the topleft point of the image as the reference point.

Reflection so far

I am slightly unhappy with how some of this code is written I feel there must be a more efficient way of calling the alien image, manipulating and positioning it differently without having to assign it multiple times. I also wonder if there is a simpler solution for flipping images about the x or y axis.


honeyp Paul Honey ~ 03 Dec 2022 12:31 p.m.

from pygame.transform import flip
alien = Actor('alien', topleft=(20, 30))                             # Load alien sprites
alien2 = Actor('alien', topright=(880, 30))
alien3 = Actor('alien', bottomleft=(20, 570))
alien4 = Actor('alien', bottomright=(880, 570))

WIDTH = 900                                                          # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

def draw():
    screen.fill((3, 70, 26))                                         # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), 'gold')    # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), 'cyan')
    alien.draw()                                                     # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)
alien = Actor("alien", topleft=(20, 30))
WIDTH = 900
HEIGHT = 600

RED = 200, 0, 0
BOX = Rect((450, 60), (50, 100))


def draw():
    screen.fill((3, 70, 26))
    screen.draw.rect(BOX, RED)
    alien.draw()


def update():
    #alien.angle = 45
    alien.angle -= 9

honeyp Paul Honey ~ 04 Dec 2022 10:03 p.m. (updated: 05 Dec 2022 11:22 a.m.)

Texting

Struggling to write on screen

Today I have been mostly failing to get text to display on screen when I click a mouse button. I was finding I could get the text to display with no issues if I added it directly into my def draw(): function, but as soon as I added my mouse click function and tried again, the text would not display.

Code
from pygame.transform import flip

alien = Actor("alien", topleft=(20, 30))                               # Load alien sprites
alien2 = Actor("alien", topright=(880, 30))
alien3 = Actor("alien", bottomleft=(20, 570))
alien4 = Actor("alien", bottomright=(880, 570))

WIDTH = 900                                                            # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), "gold")             # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), "cyan")
    alien.draw()                                                       # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)       # Flip and reposition alien sprite
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)
    #if on_mouse_down(pos):

def on_mouse_down(pos):
      screen.draw.text("hello", (300, 300))

I reasoned that the draw function is always being updated and rewritten, thus the green background is constantly being drawn over my text. Hence, when I comment out the background fill, the text is visible, as nothing else being drawn which will obscure it.

Trying something else

The rest of the day's coding was spent trying a lot of different ideas, often in desperation, all ending up with pretty much the same results. I'm just going to post some of the code configurations below, with some explanatory headings/sentences, and hopefully it'll convey my thought process.

Using on_mouse_down to call another function
from pygame.transform import flip

alien = Actor("alien", topleft=(20, 30))                               # Load alien sprites
alien2 = Actor("alien", topright=(880, 30))
alien3 = Actor("alien", bottomleft=(20, 570))
alien4 = Actor("alien", bottomright=(880, 570))

WIDTH = 900                                                            # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)


def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), "gold")             # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), "cyan")
    alien.draw()                                                       # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)       # Flip and reposition alien sprite
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)


def on_mouse_down(pos):
    set_joke_display()

def set_joke_display():
    screen.draw.text("hello", (XY))

Again, commenting out screen.fill will display the text. Also played around with just using XY for both shape size and text position.

Maybe font rendering will work...
from pygame.transform import flip
import pygame
pygame.font.init

alien = Actor("alien", topleft=(20, 30))                               # Load alien sprites
alien2 = Actor("alien", topright=(880, 30))
alien3 = Actor("alien", bottomleft=(20, 570))
alien4 = Actor("alien", bottomright=(880, 570))

BLUE = (0, 0, 200)
font = pygame.font.SysFont(None, 24)
joke = font.render('hello', True, BLUE)

WIDTH = 900                                                            # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), "gold")             # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), "cyan")
    alien.draw()                                                       # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)       # Flip and reposition alien sprite
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)

def on_mouse_down(pos):
    screen.blit(joke, (300, 300))

#def set_joke_display():

After scouring Google for assistance I cam across the following:

https://pygame.readthedocs.io/en/latest/4_text/text.html#:~:text=Pygame%20does%20not%20provide%20a%20direct%20way%20to,method%20render%20%28%29%20can%20only%20render%20single%20lines.

Here, and on one or two other sites I visited, it was mentioned that:

"Pygame does not provide a direct way to write text onto a Surface object. The method render() must be used to create a Surface object from the text, which then can be blit to the screen."

This made me think of when I'd used blit for drawing my flipped alien image surfaces in my earlier code and so I was hopeful it might yield a better result... I was left disappointed.

if only
from pygame.transform import flip
import pygame
pygame.font.init

alien = Actor("alien", topleft=(20, 30))                               # Load alien sprites
alien2 = Actor("alien", topright=(880, 30))
alien3 = Actor("alien", bottomleft=(20, 570))
alien4 = Actor("alien", bottomright=(880, 570))

BLUE = (0, 0, 200)

font = pygame.font.SysFont(None, 24)
joke = font.render('hello', True, BLUE)

WIDTH = 900                                                            # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    #screen.draw.rect(BOX, RED)                                       # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), "gold")             # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), "cyan")
    alien.draw()                                                       # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)       # Flip and reposition alien sprite
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)

    if joke():
        screen.blit(joke, (300, 300))

def on_mouse_down():
    joke = True

#def on_mouse_down(pos):

#def set_joke_display():

Unfortunately this produced the following error:

Code_grab_3.PNG

I tried many variations with if statements throughout both my mouse-click draw and render attempts, including if joke = True, and if on_mouse_down(pos):, but was ultimately left scratching my head and crying into my coffee(s).

Seeking help

At this point I had to admit defeat and emailed my mentor asking for some guidance. He introduced me to the concept of using flags and also using the global variable combined with an if statement. I will be including the email chain as part of my evidence but below is the code I have produced from the feedback:

Working Text Display
from pygame.transform import flip

alien = Actor("alien", topleft=(20, 30))                               # Load alien sprites
alien2 = Actor("alien", topright=(880, 30))
alien3 = Actor("alien", bottomleft=(20, 570))
alien4 = Actor("alien", bottomright=(880, 570))

WIDTH = 900                                                            # Window size
HEIGHT = 600

# RED = 200, 0, 0                                                      # Rectangle colour
# BOX = Rect((450, 60), (50, 100))                                     # Recangle position and size

XY = (100, 100)

TELL_JOKE = False                                                      # Flag the output (Joke) as being not true

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    #screen.draw.rect(BOX, RED)                                        # Draws rectangle
    screen.draw.filled_rect(Rect((450, 60), (XY)), "gold")             # Draws rectangle with position size and colour
    screen.draw.filled_rect(Rect((250, 150), (XY)), "cyan")
    alien.draw()                                                       # Draws alien sprite
    screen.blit(flip(alien2._surf, True, False), alien2.topleft)       # Flip and reposition alien sprite
    alien3.draw()
    screen.blit(flip(alien4._surf, True, False), alien4.topleft)

    if TELL_JOKE:                                                      # Once the Joke state has changed to true in on_mouse_down
        screen.draw.text("hello", (300, 300))                          # Display the joke on screen

def on_mouse_down():                                               # When the mouse is clicked
    global TELL_JOKE                                                   # Make the operations happening to the Joke globally available
    TELL_JOKE = True                                                   # And changes the state of the joke from false to true

At the moment this isn't particularly representative of my final project, but once I'm comfortable with the the functionality of the different elements I wish to achieve, I will start to piece it all together with those final elements.


honeyp Paul Honey ~ 07 Dec 2022 7:37 p.m. (updated: 11 Dec 2022 7:19 a.m.)

Starting to Take Shape

Making Lists and Checking them Twice

Based on what I've learned so far with regards to image/text placement/manipulation, flags, if statements and mouse clicks, I was able to create several lists of jokes, each assigned to a category and get them to print to screen based on a pushbutton associated with that category of joke. I now have something which more closely resembles my idea of a working joke generator and was able to put the elements together relatively quickly from the groundwork I'd already laid.

Code
"""
The "You're Having a Laugh" joke generator
"""
from pygame.transform import flip
import random

laugh = Actor("haha", topleft=(50, 30))                                # Load images/buttons and set their positions
animal_button = Actor("button_animals", topleft=(100, 100))
food_button = Actor("button_food", topright=(800, 100))
silly_button = Actor("button_silly", bottomleft=(100, 500))
school_button = Actor("button_school", bottomright=(800, 500))

WIDTH = 900                                                            # Window size
HEIGHT = 600

print_joke = (450, 300)                                                # Joke screen position

AUDIENCE_LAUGH = sounds.laugh1                                         # Load laughter

#List of animal jokes
ANIMAL_JOKES = ["How do you tell the difference \
between a bull and a cow? \n\nIt is either one or \
the udder!", "Why do hummingbirds hum? \n\nBecause \
they don’t know the words!", "What kind of dog does \
a magician have? \n\nA Labracadabrador!", "What do \
frogs order at fast-food restaurants? \n\nFrench \
flies!"]

#KNOCK_KNOCK_JOKES = ["Knock, knock.\nWho’s there? \
#Dozen. \nDozen who? \nDozen anyone want to let me in?"]

#List of food jokes
FOOD_JOKES = ["Which vegetable do sailors hate the \
\n\nLeeks!", "What do you call a cheese that’s not \
yours? \n\nNacho cheese!", "What kind of key opens \
a banana? \n\nA mon-key!", "Why do bees have sticky \
haie? \n\nBecause they use honeycombs!"]

#List of silly jokes
SILLY_JOKES = ["If you’re English in the kitchen \
and English in the living room, what are you in the \
bathroom? \n\nEuropean!", "What are mummies \
favourite lunches? \n\nWraps!", "What gives you the \
power to walk through a wall? \n\nA door!", "What \
happens when you wear a snow suit inside? \n\nIt \
melts all over the carpet."]

#List of school jokes
SCHOOL_JOKES = ["Why did the music teacher need a \
ladder? \n\nTo reach the high notes.", "What do \
elves learn in school? \n\nThe elf-abet!", "Why did \
the nose not want to go to school? \n\nHe was tired \
of getting picked on!", "Why did the student eat \
his homework? \n\nBecause his teacher told him it \
would be a piece of cake!"]

rect1 = (100, 100)                                                     # Background shape sizes
rect2 = (65, 125)
rect3 = (35, 30)

ANIMAL_JOKE = False                                                    # Setting flags
FOOD_JOKE = False
SILLY_JOKE = False
SCHOOL_JOKE = False                                                    

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    screen.draw.filled_rect(Rect((50, 60), rect1), "gold")             # Draw rectangles
    screen.draw.filled_rect(Rect((40, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 145), rect3), "red")
    screen.draw.filled_rect(Rect((50, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((40, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 425), rect3), "red")
    #screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    animal_button.draw()                                               # Draw pushbuttons
    food_button.draw()
    silly_button.draw()
    school_button.draw()

    if ANIMAL_JOKE:                                                      # Once the Animal Joke flag has changed to true in on_mouse_down
        laugh.draw()                                                     # Display the joke and laugh image on screen, play laughter
        screen.draw.text(random.choice(ANIMAL_JOKES), center=(print_joke))      
        AUDIENCE_LAUGH.play()

    elif FOOD_JOKE:                                                      # As per Animal flag
        laugh.draw()                                                   
        screen.draw.text(random.choice(FOOD_JOKES), center=(print_joke))      
        AUDIENCE_LAUGH.play()

    elif SILLY_JOKE:                                                      # As above
        laugh.draw()                                                    
        screen.draw.text(random.choice(SILLY_JOKES), center=(print_joke))      
        AUDIENCE_LAUGH.play()

    elif SCHOOL_JOKE:                                                     # As above
        laugh.draw()
        screen.draw.text(random.choice(SCHOOL_JOKES), center=(print_joke))
        AUDIENCE_LAUGH.play()


def on_mouse_down(pos, button):                                            # When the left mouse button is clicked on the animal button
    if button == mouse.LEFT and animal_button.collidepoint(pos):
        global ANIMAL_JOKE                                                 # Make the operations happening to the Joke flag available globally
        ANIMAL_JOKE = True                                                 # Set the animal joke flag to true

    elif button == mouse.LEFT and food_button.collidepoint(pos):           # Sets the Food joke flag to true
        global FOOD_JOKE
        FOOD_JOKE = True

    elif button == mouse.LEFT and silly_button.collidepoint(pos):          # Sets the silly joke flag to true
        global SILLY_JOKE
        SILLY_JOKE = True

    elif button == mouse.LEFT and school_button.collidepoint(pos):         # Sets the school joke glag to true
        global SCHOOL_JOKE
        SCHOOL_JOKE = True

laugh1.wav

hahaha.png

button_food.png

button_animals.png

button_reset.png

button_school.png

button_silly.png

Laughter wav file obtained from the following source:

Audience Laughter

Laughter image obtained from the following site:

Laughter Text

I created the free-use pushbuttons at the following site:

Click Minded - Button Generator

Additional Learning

The main, new topics I had to research to get to this stage were:

With the last bullet point, if I wanted to select, for example, the second joke in my FOOD_JOKES list to print every time I hit the food button, I would change

screen.draw.text(random.choice(FOOD_JOKES), center=(print_joke))

to

screen.draw.text(FOOD_JOKES[1], center=(print_joke))

Further work


honeyp Paul Honey ~ 07 Dec 2022 9:04 p.m. (updated: 08 Dec 2022 1:10 p.m.)

Tidying up my Code

So, I've just had a bit of a eureka moment with making my code a bit neater. My background as an instrumentation and controls engineer involves having to look after equipment which is controlled by PLCs. The people who program said PLCs often call entire function blocks as subroutines within other function blocks. I knew, due to the amount of repetition in my code, that I must be able to do something similar, but was a bit unsure how to do this whilst still individually addressing the unique parts of the code within those repeated lines.

I achieved this by making a global value, (JOKE) within my on_mouse_down routine. This is then assigned to a Joke category based on which button is pressed and passed to my new category_selection routine. This routine contains all the info on drawing items and playing the laughter once a particular pushbutton is pressed, with the global JOKE value taking the place of the individual joke category lists. This saves having my code repeat the same three lines at each if elif statement in my draw routine.

I also realised I could make the JOKE value and all the flags global at the very start of the on_mouse_down routine, instead of having to repeat the global assignment at the start of the mouse click if/elif routines.

Code
"""
The "You're Having a Laugh" joke generator
"""
from pygame.transform import flip
import random

laugh = Actor("haha", topleft=(50, 30))                                # Load images/buttons and set their positions
animal_button = Actor("button_animals", topleft=(100, 85))
food_button = Actor("button_food", topright=(800, 85))
silly_button = Actor("button_silly", bottomleft=(100, 515))
school_button = Actor("button_school", bottomright=(800, 515))
reset_button = Actor("button_reset", midbottom=(450, 575))

WIDTH = 900                                                            # Window size
HEIGHT = 600

print_joke = (450, 300)                                                # Joke screen position

AUDIENCE_LAUGH = sounds.laugh1                                         # Load laughter

#List of animal jokes
ANIMAL_JOKES = ["How do you tell the difference \
between a bull and a cow? \n\nIt is either one or \
the udder!", "Why do hummingbirds hum? \n\nBecause \
they don’t know the words!", "What kind of dog does \
a magician have? \n\nA Labracadabrador!", "What do \
frogs order at fast-food restaurants? \n\nFrench \
flies!"]

#KNOCK_KNOCK_JOKES = ["Knock, knock.\nWho’s there? \
#Dozen. \nDozen who? \nDozen anyone want to let me in?"]

#List of food jokes
FOOD_JOKES = ["Which vegetable do sailors hate the \
\n\nLeeks!", "What do you call a cheese that’s not \
yours? \n\nNacho cheese!", "What kind of key opens \
a banana? \n\nA mon-key!", "Why do bees have sticky \
hair? \n\nBecause they use honeycombs!"]

#List of silly jokes
SILLY_JOKES = ["If you’re English in the kitchen \
and English in the living room, what are you in the \
bathroom? \n\nEuropean!", "What are mummies \
favourite lunches? \n\nWraps!", "What gives you the \
power to walk through a wall? \n\nA door!", "What \
happens when you wear a snow suit inside? \n\nIt \
melts all over the carpet."]

#List of school jokes
SCHOOL_JOKES = ["Why did the music teacher need a \
ladder? \n\nTo reach the high notes.", "What do \
elves learn in school? \n\nThe elf-abet!", "Why did \
the nose not want to go to school? \n\nHe was tired \
of getting picked on!", "Why did the student eat \
his homework? \n\nBecause his teacher told him it \
would be a piece of cake!"]

rect1 = (100, 100)                                                     # Background shape sizes
rect2 = (65, 125)
rect3 = (35, 30)

ANIMAL_JOKE = False                                                    # Setting flags
FOOD_JOKE = False
SILLY_JOKE = False
SCHOOL_JOKE = False

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    screen.draw.filled_rect(Rect((50, 60), rect1), "gold")             # Draw rectangles
    screen.draw.filled_rect(Rect((40, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 145), rect3), "red")
    screen.draw.filled_rect(Rect((50, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((40, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 425), rect3), "red")
    screen.draw.filled_rect(Rect((750, 60), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 145), rect3), "red")
    screen.draw.filled_rect(Rect((750, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 425), rect3), "red")
    #screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    animal_button.draw()                                               # Draw pushbuttons
    food_button.draw()
    silly_button.draw()
    school_button.draw()

    if ANIMAL_JOKE:                                                      # Once the Animal Joke flag has changed to true in on_mouse_down
        category_selection()                                                     # Display the joke and laugh image on screen, play laughter

    elif FOOD_JOKE:                                                      # As per Animal flag
        category_selection()

    elif SILLY_JOKE:                                                      # As above
        category_selection()

    elif SCHOOL_JOKE:                                                     # As above
        category_selection()

    reset_button.draw()

def on_mouse_down(pos, button):
    global JOKE, SILLY_JOKE, ANIMAL_JOKE, FOOD_JOKE, SCHOOL_JOKE  # When the left mouse button is clicked on the animal button
    if button == mouse.LEFT and animal_button.collidepoint(pos):
        ANIMAL_JOKE = True
        JOKE = ANIMAL_JOKES  # Set the animal joke flag to true

    elif button == mouse.LEFT and food_button.collidepoint(pos):           # Sets the Food joke flag to true
        FOOD_JOKE = True
        JOKE = FOOD_JOKES

    elif button == mouse.LEFT and silly_button.collidepoint(pos):          # Sets the silly joke flag to true
        SILLY_JOKE = True
        JOKE = SILLY_JOKES

    elif button == mouse.LEFT and school_button.collidepoint(pos):         # Sets the school joke glag to true
        SCHOOL_JOKE = True
        JOKE = SCHOOL_JOKES

def category_selection():
    laugh.draw()
    screen.draw.text(random.choice(JOKE), center=(print_joke))
    AUDIENCE_LAUGH.play()

honeyp Paul Honey ~ 10 Dec 2022 7:33 p.m. (updated: 10 Dec 2022 7:52 p.m.)

First Submission

More struggles

I have been looking at ways to try and get my reset button to start the program over but I have been coming up blank. One method I played around with is below. I separated my draw function branching off a separate function which contained just the joke category flag manipulations. I added a function at the start which just calls the draw function, I then also added a restart function at the end which I tried, using flags to loop back around to the starting function in order to reset the entire thing. Obviously this didn't work.

Code
WIDTH = 900
HEIGHT = 600
"""
The "You're Having a Laugh" joke generator
"""
#from pygame.transform import flip
import random

laugh = Actor("haha", topleft=(50, 30))                                # Load images/buttons and set their positions
animal_button = Actor("button_animals", topleft=(100, 85))
food_button = Actor("button_food", topright=(800, 85))
silly_button = Actor("button_silly", bottomleft=(100, 515))
school_button = Actor("button_school", bottomright=(800, 515))
reset_button = Actor("button_reset", midbottom=(450, 575))

WIDTH = 900                                                            # Window size
HEIGHT = 600

print_joke = (450, 300)                                                # Joke screen position

audience_laugh = sounds.laugh1
#transparent = (0, 0, 0, 0)# Load laughter

#List of animal jokes
animal_jokes = ["How do you tell the difference \
between a bull and a cow? \n\nIt is either one or \
the udder!", "Why do hummingbirds hum? \n\nBecause \
they don’t know the words!", "What kind of dog does \
a magician have? \n\nA Labracadabrador!", "What do \
frogs order at fast-food restaurants? \n\nFrench \
flies!"]

#KNOCK_KNOCK_JOKES = ["Knock, knock.\nWho’s there? \
#Dozen. \nDozen who? \nDozen anyone want to let me in?"]

#List of food jokes
food_jokes = ["Which vegetable do sailors hate the \
\n\nLeeks!", "What do you call a cheese that’s not \
yours? \n\nNacho cheese!", "What kind of key opens \
a banana? \n\nA mon-key!", "Why do bees have sticky \
hair? \n\nBecause they use honeycombs!"]

#List of silly jokes
silly_jokes = ["If you’re English in the kitchen \
and English in the living room, what are you in the \
bathroom? \n\nEuropean!", "What are mummies \
favourite lunches? \n\nWraps!", "What gives you the \
power to walk through a wall? \n\nA door!", "What \
happens when you wear a snow suit inside? \n\nIt \
melts all over the carpet."]

#List of school jokes
school_jokes = ["Why did the music teacher need a \
ladder? \n\nTo reach the high notes.", "What do \
elves learn in school? \n\nThe elf-abet!", "Why did \
the nose not want to go to school? \n\nHe was tired \
of getting picked on!", "Why did the student eat \
his homework? \n\nBecause his teacher told him it \
would be a piece of cake!"]

rect1 = (100, 100)                                                     # Background shape sizes
rect2 = (65, 125)
rect3 = (35, 30)

animal_joke = False                                                    # Setting flags
food_joke = False
silly_joke = False
school_joke = False
start = True

def tell_a_joke():
    start = False
    draw()

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    screen.draw.filled_rect(Rect((50, 60), rect1), "gold")             # Draw rectangles
    screen.draw.filled_rect(Rect((40, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 145), rect3), "red")
    screen.draw.filled_rect(Rect((50, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((40, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 425), rect3), "red")
    screen.draw.filled_rect(Rect((750, 60), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 145), rect3), "red")
    screen.draw.filled_rect(Rect((750, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 425), rect3), "red")
    #screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    animal_button.draw()                                               # Draw pushbuttons
    food_button.draw()
    silly_button.draw()
    school_button.draw()
    Tell_Joke()

def on_mouse_down(button, pos):
    global JOKE, animal_joke, food_joke, silly_joke, school_joke # When the left mouse button is clicked on the animal button
    if button == mouse.LEFT and animal_button.collidepoint(pos):
        animal_joke = True
        JOKE = animal_jokes  # Set the animal joke flag to true

    elif button == mouse.LEFT and food_button.collidepoint(pos):           # Sets the Food joke flag to true
        food_joke = True
        JOKE = food_jokes

    elif button == mouse.LEFT and silly_button.collidepoint(pos):          # Sets the silly joke flag to true
        silly_joke = True
        JOKE = silly_jokes

    elif button == mouse.LEFT and school_button.collidepoint(pos):         # Sets the school joke flag to true
        school_joke = True
        JOKE = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        restart()

def Tell_Joke():
    if animal_joke:                                                      # Once the Animal Joke flag has changed to true in on_mouse_down
        selected_joke()                                                     # Display the joke and laugh image on screen, play laughter

    elif food_joke:                                                      # As per Animal flag
        selected_joke()

    elif silly_joke:                                                      # As above
        selected_joke()

    elif school_joke:                                                     # As above
        selected_joke()


def selected_joke():
    laugh.draw()
    screen.draw.text(random.choice(JOKE), center=(print_joke))
    audience_laugh.play()
    reset_button.draw()
    restart()

def restart():
    global start
    start = True

I also tried having a main(): function at the start, indenting everything below to be a part of just this function and then attempting to loop back around to that at the end, with no success. I also tried making certain elements transparent when the reset button was clicked on but again had no luck.

Submission

As a result of the above issues, I have decided to enter the last known "good" bit of code so that I can get some feedback and hopefully some hints to point me in the right direction with a few unfinished items and things I'm unhappy with.

The code was written using the mu editor in PygameZero mode, so it is probably best run in this mode. Once the game window opens, clicking on a category of joke will randomly display a joke based on said category accompanied by laughter.

Below is what I have so far:

Code
"""
The "You're Having a Laugh" joke generator
"""
#from pygame.transform import flip
import random

laugh = Actor("haha", topleft=(50, 30))                                # Load images/buttons and set their positions
animal_button = Actor("button_animals", topleft=(100, 85))
food_button = Actor("button_food", topright=(800, 85))
silly_button = Actor("button_silly", bottomleft=(100, 515))
school_button = Actor("button_school", bottomright=(800, 515))
reset_button = Actor("button_reset", midbottom=(450, 575))

WIDTH = 900                                                            # Window size
HEIGHT = 600

print_joke = (450, 300)                                                # Joke screen position

audience_laugh = sounds.laugh1                                         # Load laughter

#List of animal jokes
animal_jokes = ["How do you tell the difference \
between a bull and a cow? \n\nIt is either one or \
the udder!", "Why do hummingbirds hum? \n\nBecause \
they don’t know the words!", "What kind of dog does \
a magician have? \n\nA Labracadabrador!", "What do \
frogs order at fast-food restaurants? \n\nFrench \
flies!"]

#KNOCK_KNOCK_JOKES = ["Knock, knock.\nWho’s there? \
#Dozen. \nDozen who? \nDozen anyone want to let me in?"]

#List of food jokes
food_jokes = ["Which vegetable do sailors hate the \
\n\nLeeks!", "What do you call a cheese that’s not \
yours? \n\nNacho cheese!", "What kind of key opens \
a banana? \n\nA mon-key!", "Why do bees have sticky \
hair? \n\nBecause they use honeycombs!"]

#List of silly jokes
silly_jokes = ["If you’re English in the kitchen \
and English in the living room, what are you in the \
bathroom? \n\nEuropean!", "What are mummies \
favourite lunches? \n\nWraps!", "What gives you the \
power to walk through a wall? \n\nA door!", "What \
happens when you wear a snow suit inside? \n\nIt \
melts all over the carpet."]

#List of school jokes
school_jokes = ["Why did the music teacher need a \
ladder? \n\nTo reach the high notes.", "What do \
elves learn in school? \n\nThe elf-abet!", "Why did \
the nose not want to go to school? \n\nHe was tired \
of getting picked on!", "Why did the student eat \
his homework? \n\nBecause his teacher told him it \
would be a piece of cake!"]

rect1 = (100, 100)                                                     # Background shape sizes
rect2 = (65, 125)
rect3 = (35, 30)

animal_joke = False                                                    # Setting flags
food_joke = False
silly_joke = False
school_joke = False

def draw():
    screen.fill((3, 70, 26))                                           # Set window background colour
    screen.draw.filled_rect(Rect((50, 60), rect1), "gold")             # Draw rectangles for background
    screen.draw.filled_rect(Rect((40, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 145), rect3), "red")
    screen.draw.filled_rect(Rect((50, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((40, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 425), rect3), "red")
    screen.draw.filled_rect(Rect((750, 60), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 145), rect3), "red")
    screen.draw.filled_rect(Rect((750, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 425), rect3), "red")
    #screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    animal_button.draw()                                               # Draw pushbuttons
    food_button.draw()
    silly_button.draw()
    school_button.draw()

    if animal_joke:                                                    # Once the Animal Joke flag has changed to true in on_mouse_down
        category_selection()                                           # Run the category_selection function

    elif food_joke:                                                    # As per Animal flag
        category_selection()

    elif silly_joke:                                                   # As above
        category_selection()

    elif school_joke:                                                  # As above
        category_selection()

def on_mouse_down(pos, button):
    global JOKE, animal_joke, food_joke, silly_joke, school_joke       # When the left mouse button is clicked on the animal button
    if button == mouse.LEFT and animal_button.collidepoint(pos):       # Set the animal joke flag to true
        animal_joke = True
        JOKE = animal_jokes  

    elif button == mouse.LEFT and food_button.collidepoint(pos):       # Sets the Food joke flag to true
        food_joke = True
        JOKE = food_jokes

    elif button == mouse.LEFT and silly_button.collidepoint(pos):      # Sets the silly joke flag to true
        silly_joke = True
        JOKE = silly_jokes

    elif button == mouse.LEFT and school_button.collidepoint(pos):     # Sets the school joke flag to true
        school_joke = True
        JOKE = school_jokes

def category_selection():                                              # Tell the joke
    laugh.draw()
    screen.draw.text(random.choice(JOKE), center=(print_joke))         # Pics a random joke from the category selected by the user 
    audience_laugh.play()
    reset_button.draw()                                                # To be used for starting over

Things I'd like to improve upon


honeyp Paul Honey ~ 10 Dec 2022 7:38 p.m.

Code_grades_emails.eml


ntoll Nicholas Tollervey ~ 14 Dec 2022 2:11 p.m.

Hi Paul,

First of all, many congratulations on getting your project this far. My job, as mentor, will be to help you improve the code, support you as you refine the project and, ultimately, assess the project against the requirements for grade 1. Reading your project diary tells me you've had quite an adventure and I've thoroughly enjoyed following along with your triumphs, trials and tribulations. Let's see how we can get things in a great shape for both your son (most importantly), and the requirements for grading!

I've copied your code into Mu, and downloaded all the game assets. My first slight niggle (but very easy to fix) was that the hahaha.png was actually referred to in the code as haha. Hence PyGameZero couldn't find it. I simply renamed hahaha.png to haha.png and it worked.

I have to admit, for the first five minutes I just sat at my computer grinning like the Cheshire Cat. 😁 The colourful user interface, the canned laughter, the fondue cheesiness of the jokes... 🧀 as a dad with joke loving kids, this project has hit all the right notes for me. 🤡

I really appreciated how you told the story of creating your project. Your writing is thoughtful, engaging and clearly demonstrates how you have learned the necessary Python to deliver your project and meet the requirements for grade 1. Really well done..! This is the sort of evidence I want to see as a mentor assessing the project for grading. Keep up the good work in this respect.

I have some feedback on the code (I'm taking the most recent version as my starting point):

def my_function():
    """
    This is where I write my comments for the function.

    It can be over several lines.
    """
    return "Hello"
my_jokes = [
    ["setup 1", "punchline 1"],
    ["setup 2", "punchline 2"],
    # ... etc ...
]

my_other_jokes = [
    ["setup 3", "punchline 3"],
    ["setup 4", "punchline 4"],
    # ... etc ...
]

and to select the joke:

the_joke = "\n\n".join(random.choice(my_jokes))

The "\n\n".join(...) bit simply tells Python to join the two parts of the list (containing the setup and punchline for the randomly selected joke) together with newlines ("\n\n"). So, the list ("setup", "punchline") becomes "setup\n\npunchline".

I've really enjoyed reading about your project so far, and exploring your code too. I think this could evolve into a really funky project. I also hope my feedback and suggestions make sense. If in doubt, just ask here and I'll reply. In addition to assessing your project, I'm also here to help and the interactions we have also form part of the basis of my assessment. So just dive in and let me know how you get on.

Bravo on everything so far, and I look forward to seeing how this shapes up.

🚀


honeyp Paul Honey ~ 19 Dec 2022 11:44 p.m. (updated: 19 Dec 2022 11:52 p.m.)

Trying to refine my project

Comment Tidy-up

Based on assessor feedback I have managed to drastically tidy up my code. I had previously used the Mu "Check" function, and could see that I was getting error messages about my code being too long on certain lines. However, because it didn't stop my game from running, and mainly because I was being pig headed with how I was used to representing comments from my limited machine coding exposure, I kept the comments using hash-tags off to the right of my code. This is often how a lot of comments are presented by the programmers who write the PLC code, using statement lists, for the equipment on which I work. Therefore I just reverted to what I was used to.

I see now it is much better just to use triple quotes at the start of a function to give a brief description. Especially, as you've mentioned Nicholas, if the code is relatively self explanatory. I think I was also commenting everything from the point of view that the person reading it might have zero experience and so explaining everything might be advantageous.

Cutting out Unnecessary Code

Based on my mentor's advice, I replaced my individual flags with a single tell_joke flag. This single flag is set to true regardless of which button is clicked on, which is still used to select which list of jokes is selected for random joke display. This has meant I can get rid of all the elif statements in my draw function. Therefore:

if animal_joke:
    category_selection()

elif food_joke:
    category_selection()

elif silly_joke:
    category_selection()

elif school_joke:
    category_selection()

Has been replaced with:

if tell_joke:
        laugh.draw()
        bean.draw()
        screen.draw.text("\n\n".join(random.choice(JOKE)), center=(print_joke), fontname="rabbit_on_the_moon", fontsize=36,
        color="#AAFF00")  #, gcolor="#66AA00", owidth=1.5, ocolor="black", alpha=0.8)
        audience_laugh.play()
        reset_button.draw()

As a result of the slim-lining advice given, I could see that this single if statement could replace the separate category_selection function I had previously written. I've also incorporated the advice to separate my joke setups and punchlines in each list so they may be read more easily in the code, hence the "\n\n".join part of the above code.

Playing around with Fonts

You can also see in the above code that I've tried to play around with how my joke text. Just to start me off I copied some of the text formatting code from the Pygame Zero tutorial site linked to me by Nicholas:

Text Formatting Docs

Unfortunately I was presented with the following error upon clicking one of the joke category pushbuttons:

pygame 2.1.2 (SDL 2.0.18, Python 3.8.12)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "C:\Local\Programs\MUEDIT~1\Python\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Local\Programs\MUEDIT~1\Python\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\__main__.py", line 3, in <module>
    main()
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\runner.py", line 93, in main
    run_mod(mod)
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\runner.py", line 113, in run_mod
    PGZeroGame(mod).run()
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\game.py", line 217, in run
    self.mainloop()
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\game.py", line 256, in mainloop
    draw()
  File "paul honey grade 1 - joke generator.py", line 97, in draw
    screen.draw.text("\n\n".join(random.choice(JOKE)), center=(print_joke), fontname="rabbit_on_the_moon", fontsize=36,
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\screen.py", line 61, in text
    ptext.draw(*args, surf=self._surf, **kwargs)
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\ptext.py", line 439, in draw
    tsurf = getsurf(text, fontname, fontsize, sysfontname, bold, italic, underline, width, widthem,
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\ptext.py", line 280, in getsurf
    surf0 = getsurf(text, fontname, fontsize, sysfontname, bold, italic, underline,
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\ptext.py", line 311, in getsurf
    surf0 = getsurf(text, fontname, fontsize, sysfontname, bold, italic, underline,
  File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\ptext.py", line 349, in getsurf
    (1.0 - m) * array[:, :, j] + m * gcolor[j]).astype(array.dtype)
ValueError: operands could not be broadcast together with shapes (50,) (0,49) 

I narrowed the error down to the colour gradient portion. Once this was removed, the code ran without error.

The Changes so Far

I have not finished implementing all the changes I wish to make. My son has found a selection of funny images for me to use from https://openclipart.org/, which I've started to include. We have also bought him a joke book for Christmas, which hopefully he can use to populate the program with his own jokes, once I have written a how to guide. Below is my altered code, it's not yet ready for further review, but it's getting late and just wanted to make sure I'd logged everything I'd done so far whilst still fresh in my mind.

Code
"""
The "You're Having a Laugh" joke generator
"""
# from pygame.transform import flip
import random

laugh = Actor("haha", topleft=(50, 30))  # Load images/buttons and set their positions
bean = Actor("bean", bottomright=(900, 600))
animal_button = Actor("button_animals", topleft=(100, 85))
food_button = Actor("button_food", topright=(800, 85))
silly_button = Actor("button_silly", bottomleft=(100, 515))
school_button = Actor("button_school", bottomright=(800, 515))
reset_button = Actor("button_reset", midbottom=(450, 575))

WIDTH = 900  # Window size
HEIGHT = 600

print_joke = (450, 300)  # Joke screen position

audience_laugh = sounds.laugh1  # Load laughter

animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!",
    ],
    ["Why do hummingbirds hum?", "Because they don’t know the words!"],
    ["What kind of dog does a magician have?", "A Labracadabrador!"],
    ["What do frogs order at fast-food restaurants", "French flies!"],
]

# KNOCK_KNOCK_JOKES = ["Knock, knock.\nWho’s there? \
# Dozen. \nDozen who? \nDozen anyone want to let me in?"]

food_jokes = [
    ["Which vegetable do sailors hate the most?", "Leeks!"],
    ["What do you call a cheese that’s not yours?" "Nacho cheese!"],
    ["What kind of key opens a banana?", "A mon-key!"],
    ["Why do bees have sticky hair?, Because they use honeycombs!"],
]

silly_jokes = [
    [
        "If you’re English in the kitchen and English in the living room, \n\nwhat are you in the bathroom?",
        "European!",
    ],
    ["What are mummies favourite lunches?", "Wraps!"],
    ["What gives you the power to walk through a wall?", "A door!"],
    ["What happens when you wear a snow suit inside?", "It melts all over the carpet."],
]

# List of school jokes
school_jokes = [
    ["Why did the music teacher need a ladder?", "To reach the high notes."],
    ["What do elves learn in school?", "The elf-abet!"],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!",
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!",
    ],
]

rect1 = (100, 100)  # Background shape sizes
rect2 = (65, 125)
rect3 = (35, 30)

tell_joke = False

def draw():
    screen.fill((3, 70, 26))  # Set window background colour
    screen.draw.filled_rect(
        Rect((50, 60), rect1), "gold"
    )  # Draw rectangles for background
    screen.draw.filled_rect(Rect((40, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 145), rect3), "red")
    screen.draw.filled_rect(Rect((50, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((40, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((95, 425), rect3), "red")
    screen.draw.filled_rect(Rect((750, 60), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 75), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 145), rect3), "red")
    screen.draw.filled_rect(Rect((750, 440), rect1), "gold")
    screen.draw.filled_rect(Rect((795, 400), rect2), "cyan")
    screen.draw.filled_rect(Rect((770, 425), rect3), "red")
    # screen.blit(flip(alien2._surf, True, False), alien2.topleft)
    animal_button.draw()  # Draw pushbuttons
    food_button.draw()
    silly_button.draw()
    school_button.draw()

    if tell_joke:
        laugh.draw()
        bean.draw()
        screen.draw.text("\n\n".join(random.choice(JOKE)), center=(print_joke), fontname="rabbit_on_the_moon", fontsize=36,
        color="#AAFF00", owidth=1.5, ocolor="black", alpha=0.8)
        audience_laugh.play()
        reset_button.draw()  # Run the category_selection function


def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global JOKE, tell_joke  # food_joke, silly_joke, school_joke
    if button == mouse.LEFT and animal_button.collidepoint(pos):
        tell_joke = True
        JOKE = animal_jokes

    elif button == mouse.LEFT and food_button.collidepoint(pos):
        tell_joke = True
        JOKE = food_jokes

    elif button == mouse.LEFT and silly_button.collidepoint(pos):
        tell_joke = True
        JOKE = silly_jokes

    elif button == mouse.LEFT and school_button.collidepoint(pos):
        tell_joke = True
        JOKE = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        tell_joke = ""

NB: I've now also got a working reset button, which just sets my flag back to false to remove everything implemented when the category buttons are clicked. I notice it doesn't cut the audio off however, and jokes are still cycled through if a click is made elsewhere on the screen. As previously mentioned, I just want the entire screen, apart from the reset button, to become inactive once a joke is told. Therefore I still need to work on this.


ntoll Nicholas Tollervey ~ 21 Dec 2022 6:16 p.m.

Hi Paul,

Thank you so much for the updates, and well done on making such good progress towards a version of the project that simplifies how it works, and does so more efficiently. I have some feedback and reminders/requests for further refinement:

KeyError: "No image found like 'bean'. Are you sure the image exists?"

I'm looking forward to seeing how this shapes up further, what further refinements you may make and how your son finds using it. Very much in the spirit of a Christmas cracker for the 21st century.


honeyp Paul Honey ~ 03 Jan 2023 5:24 a.m. (updated: 03 Jan 2023 6:46 a.m.)

Debug

With regards to the previous error code, at the portion shown below:

 File "C:\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\ptext.py", line 349, in getsurf
    (1.0 - m) * array[:, :, j] + m * gcolor[j]).astype(array.dtype)
ValueError: operands could not be broadcast together with shapes (50,) (0,49)

The part of the message gcolor[j]).astype(array.dtype) led me to believe it was an issue with the colour gradient part of the code. I commented out this part of the code using a #, which also removed the subsequent code for outline thickness, colour and how transparent the text was. When running my code with this removed the text would display with no issues. I then just deleted the gcolour part and put the outline and transparency settings back in, to check these wouldn't cause any issues, which they did not. I have decided to remove transparency and just have the text solid however. As I think this looks better.

Updated Code

After the assessor feedback I have altered my code to the following:

"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 0))
mic = Actor("micstand", center=(430, 375))

laugh = Actor("haha", center=(450, 300))    # Randomly generated images
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [laugh, bean, lol, rofl]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 1 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 2 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

joke = False

def draw():
    stage.draw()
    neon_mic.draw()
    mic.draw()
    buttons[0].draw()
    buttons[1].draw()
    buttons[2].draw()
    buttons[3].draw()

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""      

Code update justifications

I removed the separate line of code which sets the position of the joke and just set it's position to 450, 300 in the draw function.

[
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],

I have laid each of the jokes out in this way, despite the tidy button rearranging how they're displayed, to make it easier for a user to change the joke setups and punchlines. Otherwise Mu will tidy the code to look like the following:

[
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!",
    ],
    ["Why do hummingbirds hum?", "Because they don't know the words!"],

Having a mixture of how the code is arranged, due to line length, I found to be visually jarring. I felt it might be confusing for the user, should they wish to replace the current jokes with their own, to have two different layouts to contend with.

I have renamed the buttons from their category names to their physical positions when displayed on screen. This is so that if the user wishes to create their own categories, they can create a new pushbutton, place it into the images folder and they only have one small piece of code to change e.g. top_left_button = Actor("button_animals", topleft=(100, 150)) can become top_left_button = Actor("button_holidays", topleft=(100, 150)), instead of having to go all the way through the code and change several instances where a button name has been used. Obviously they would also need to change the name of the corresponding joke list. But this will all be detailed in the user guide I am currently putting together.

I put all the buttons into a list, as I was hoping to be able to just draw all list items at once. I tried the following:

buttons[0, 1, 2, 3].draw()

However I get the following error message:

pygame 2.1.2 (SDL 2.0.18, Python 3.8.12)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "C:\Users\406850\AppData\Local\Programs\MUEDIT~1\Python\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\406850\AppData\Local\Programs\MUEDIT~1\Python\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\406850\AppData\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\__main__.py", line 3, in <module>
    main()
  File "C:\Users\406850\AppData\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\runner.py", line 93, in main
    run_mod(mod)
  File "C:\Users\406850\AppData\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\runner.py", line 113, in run_mod
    PGZeroGame(mod).run()
  File "C:\Users\406850\AppData\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\game.py", line 217, in run
    self.mainloop()
  File "C:\Users\406850\AppData\Local\python\mu\mu_venv-38-20221122-201713\lib\site-packages\pgzero\game.py", line 256, in mainloop
    draw()
  File "paul honey grade 1 - joke generator.py", line 124, in draw
    buttons[0, 1, 2, 3].draw()
TypeError: list indices must be integers or slices, not tuple


---------- FINISHED ----------
exit code: 1 status: 0

I have not been able to decipher why pygame won't accept this, but will allow each item in the list to be drawn separately. I tried just drawing one button at first, then tried different methods to add in one more at a time, but was unsuccessful. When I only had one button on screen I noticed that if I clicked the positions where the other buttons should have been, their respective jokes still displayed. Is that because my pygame mouse click command is looking for a click at the position of where the button would be, regardless of whether it has actually been drawn?

I have left the buttons in a list for the minute. This is in the hopes I can make the draw section of the code more concise if all list items can be drawn with just one line of code. However, I will remove the list and just draw each button individually if necessary.

I have also put some more images into a list to be drawn at random after the program detects the mouse click. At first, I couldn't get them to display without crashing the program, this was just with writing draw(random.choice(funny_image)) within the draw function. After some research it looked like I needed to assign the randomly generated image to another parameter. I tried putting the assignment at the beginning of the code, i.e. outside of the draw function, but this caused only the same, randomly selected image to be displayed each time a joke button was pressed, even after pushing the reset button.

I needed to put both of the following lines of code into the if joke section of the draw function in order to have a new image selected at random each time.

draw_image = random.choice(funny_image)
draw_image.draw()

I hope this all makes sense. I am currently working nightshifts with an awful cold and so my explanations and grammar might not be up to par. But I hope I've explained myself coherently enough.

I am currently writing a user guide, but wanted to get my latest code updates critiqued, as something close to my finalised code will need to be included within said guide.

My son picked some of the images for me to include when the joke is randomly generated, including the Mr Bean image, which caused him to burst out laughing when he found it on the clipart website.

I will also provide links to all the extra images and sounds I have gathered for my program.

laugh2.wav

drum.wav

slow_clap.wav

stage.png

bean.png

micstand.png

lol.png

neon_mic.png

rofl.png


honeyp Paul Honey ~ 04 Jan 2023 4:47 a.m. (updated: 04 Jan 2023 5:37 a.m.)

Further Revision

List Drawing

After Googling the error I was receiving when trying to draw my entire list list object has no attribute draw, I discovered I could draw an entire set of list items at once using a for loop:

def draw
      [backgrounds.draw() for backgrounds in background_images]
      [joke_categories.draw() for joke_categories in buttons]

Here I have now assigned all my background images and pushbuttons to their own lists in order to draw them all at once. As I understand it, an ordinary list can't have draw attributed to it, however individual list items may. This is why my previous buttons[0].draw() code would work but buttons[0:3].draw() would return an error. My new code now reassigns each individual list item, in order that they may all be drawn at once.

Error Handling

I tried reordering the code to the following:

def draw
      [for backgrounds in background_images backgrounds.draw()]

To me this makes more sense "grammatically" so I thought I would test it out. However, I was greeted with a syntax error:

    [for backgrounds in background_images backgrounds.draw()]
     ^
SyntaxError: invalid syntax

A syntax error occurs when the code is initially executed, known as parsing (Invalid Syntax). Python cannot understand what is written and so returns an error straight away. This differs from some of my earlier errors, for example when I tried to include coding for displayed text colour gradients, which would cause my program to crash, after initially running, when trying to interact with it. This would be considered a runtime error i.e. unexpectedly exiting the program when an error occurs trying to execute a specific line of code (Runtime Error examples).

Although, at present, I don't know the specifics behind why the line of code in question has to be ordered the way it does to prevent the syntax error in question.

New Code
"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 195))
mic = Actor("micstand", center=(430, 375))
comedy = Actor("comedy", center=(450, 70))
laugh_emoji = Actor("laugh_emoji", midright=(880, 280))
laugh_emoji.angle = -30
background_images = [stage, comedy, neon_mic, mic, laugh_emoji]

laugh = Actor("hahaha", center=(450, 300))    # Randomly generated images
haha = Actor("haha", center=(400,300))
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [laugh, bean, lol, rofl, haha]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 1 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 2 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

joke = False

def draw():
    [backgrounds.draw() for backgrounds in background_images]
    [joke_categories.draw() for joke_categories in buttons]

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""

I have now added in more background images, all of which are able to be drawn by just adding them into my list. The following links are for all the additional images and sounds which are now present in my program:

Comedy sign haha Neon laugh emoji ROFL Neon mic Mic Stand Stage Slow Clap Comedy Drums Girl's Laugh

Next Steps

I think I will re-upload all my images/sounds etc. in zip files as evidence, just to make sure I haven't missed anything. I will also finish off my user guide for submission and perhaps email everything back home to see if my son is able to have a go at running/customising the program whilst I'm not there.

I will also not be 100% happy with my program unless I can work out how to make my the entire screen inactive apart from the reset button once the reset button displays, thus forcing the user to reset each time in order to then be able to activate another joke. I am quite happy with how I have progressed so far though.


ntoll Nicholas Tollervey ~ 07 Jan 2023 5:16 p.m.

Hi Paul,

It's great to see this progress, and the app is looking and feeling a lot more polished. Well done. I also appreciate the explanations for why you take one approach rather than another. I have a few points of feedback, explanations and questions for you.

new_list = [do_something(x) for x in some_other_list]

This is a rather good introductory guide. While you're not assigning the result of your list comprehension, it is being evaluated and you are doing something in the "do_something" part of it... i.e. the background.draw() call.

The reason you were getting a syntax error is simply because it looked like you were trying to write a list comprehension, but you weren't writing it in the way Python expected (i.e. the syntax was wrong). I hope the article to which I link throws more light on the subject, and please don't hesitate to ask if you want to know more. (Aside: deliberate use of list comprehensions is not expected until grade 4.)

It feels like this is VERY close to being in a place where I can make an assessment, give you a mark and (most importantly) the written feedback about how you've got on. From my point of view, I think I'm waiting on:

Keep up the good work..! You're almost there.


honeyp Paul Honey ~ 09 Jan 2023 8:47 a.m.

Tying everything together

I think I'm at a point now where I'm happy with everything. I've stopped worrying about disabling the screen before resetting. I think children my son's ago will get some enjoyment from it regardless.

To that end I've emailed both my kids my user guide, which has all the files they need attached in the word document, to get their feedback. Hopefully this'll act as a little product test. My youngest is 10 and my eldest 14, so I've asked him to help his brother if he gets stuck and mum isn't able. I have also told him to have a go at messing around with the code and program on his own though.

There are a bunch of extra images in my user guide, one of which I've added to my generator, swapping out one of the previous images. These images are all just stock pictures I pulled from Word.

I hope everything is present and correct. Please let me know if something seems like it's missing. I'm unsure when the children might get around to trying it out, but if you'd like to wait for their feedback before grading then I can attach it as evidence later on.

I have perhaps been a bit obvious with some of the descriptions within my code, when using the tripple quotes, but this is because I'm hoping it'll make it a little easier for primary school children to navigate around code when broken up into sections with their own headings.

The Code
"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

joke = False

"""
Section 1 - Backgrounds, popups and sounds
"""

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 195))
mic = Actor("micstand", center=(430, 375))
comedy = Actor("comedy", center=(450, 70))
laugh_emoji = Actor("laugh_emoji", midright=(880, 280))
laugh_emoji.angle = -30
background_images = [stage, comedy, neon_mic, mic, laugh_emoji]

raspberry = Actor("raspberry", topright=(485, 125))    # Randomly generated images
haha = Actor("haha", center=(400,300))
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [raspberry, haha, bean, lol, rofl]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 2 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 3 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

"""
Section 4 - The code which tells your jokes
"""

def draw():
    [backgrounds.draw() for backgrounds in background_images]
    [joke_categories.draw() for joke_categories in buttons]

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""

Rabbit_on_the_Moon_Font.zip

Joke_Generator_Images.zip

Joke_Generator_Sounds.zip

Joke_Generator_User_Guide.docx

Joke_Generator_User_Guide.pdf

Email_to_children_1.PNG

Email_to_children_2.PNG


honeyp Paul Honey ~ 09 Jan 2023 11:10 p.m.

Code Adjustment

I've decided to make a slight adjustment to my code, just in the way things are ordered. Originally I hadn't planned on having a section in the guide for customising the various background images, popups and sounds. This is why I included it at the beginning of the code, instead of grouped with the other images. However it has been niggling at me that all the background/popup images, as well as the category buttons, aren't more or less grouped together. Especially now they have instructions in the guide for customisation.

Therefore, I've updated the code and the user guide, and re-uploaded below. I think this will flow better in the user guide for anyone reading it as well.

Code
"""
The "You're Having a Laugh" Joke Generator
"""

import random

WIDTH = 900  # Window size
HEIGHT = 600

joke = False

"""
Section 1 - Joke Lists
Add your own!
"""
animal_jokes = [
    [
        "How do you tell the difference between a bull and a cow?",
        "It is either one or the udder!"
    ],
    [
        "Why do hummingbirds hum?",
        "Because they don't know the words!"
    ],
    [
        "What kind of dog does a magician have?",
        "A Labracadabrador!"
    ],
    [
        "What do frogs order at fast-food restaurants",
        "French flies!"
    ],
]

food_jokes = [
    [
        "Which vegetable do sailors hate the most?",
        "Leeks!"
    ],
    [
        "What do you call a cheese that's not yours?",
        "Nacho cheese!"
    ],
    [
        "What kind of key opens a banana?",
        "A mon-key!"
    ],
    [
        "Why do bees have sticky hair?",
        "Because they use honeycombs!"
    ],
]

silly_jokes = [
    [
        "If you're English in the kitchen and English in the living room,\
        \n\nwhat are you in the bathroom?",
        "European!"
    ],
    [
        "What are mummies favourite lunches?",
        "Wraps!"
    ],
    [
        "What gives you the power to walk through a wall?",
        "A door!"
    ],
    [
        "What happens when you wear a snow suit inside?",
        "It melts all over the carpet."
    ],
]

school_jokes = [
    [
        "Why did the music teacher need a ladder?",
        "To reach the high notes."
    ],
    [
        "What do elves learn in school?",
        "The elf-abet!"
    ],
    [
        "Why did the nose not want to go to school?",
        "He was tired of getting picked on!"
    ],
    [
        "Why did the student eat his homework?",
        "Because his teacher told him it would be a piece of cake!"
    ],
]

"""
Section 2 - Buttons list
Can you think of your own categories?
"""
top_left_button = Actor("button_animals", topleft=(100, 150))
top_right_button = Actor("button_food", topright=(800, 150))
bottom_left_button = Actor("button_silly", bottomleft=(100, 450))
bottom_right_button = Actor("button_school", bottomright=(800, 450))
reset_button = Actor("button_reset", midbottom=(450, 575))
buttons = [top_left_button, top_right_button, bottom_left_button, bottom_right_button]

"""
Section 3 - Backgrounds, popups and sounds
"""

stage = Actor("stage", midtop=(450, 0))     # Background images
neon_mic = Actor("neon_mic", topleft=(0, 195))
mic = Actor("micstand", center=(430, 375))
comedy = Actor("comedy", center=(450, 70))
laugh_emoji = Actor("laugh_emoji", midright=(880, 280))
laugh_emoji.angle = -30
background_images = [stage, comedy, neon_mic, mic, laugh_emoji]

raspberry = Actor("raspberry", topright=(485, 125))    # Randomly generated images
haha = Actor("haha", center=(400,300))
bean = Actor("bean", bottomright=(900, 600))
lol = Actor("lol", center=(375, 300))
rofl = Actor("rofl", center=(430, 400))
funny_image = [raspberry, haha, bean, lol, rofl]

audience_laugh = sounds.laugh1      # Randomly generated sounds
girl_laugh = sounds.laugh2
badum_tish = sounds.drum
slow_clap = sounds.slow_clap
funny_sound = [audience_laugh, girl_laugh, badum_tish, slow_clap]

"""
Section 4 - The code which tells your jokes
"""

def draw():
    [backgrounds.draw() for backgrounds in background_images]
    [joke_categories.draw() for joke_categories in buttons]

    if joke:
        """
        After joke category is selected,
        display random joke and images,
        play random sound.
        """
        draw_image = random.choice(funny_image)
        draw_image.draw()
        screen.draw.text(
            "\n\n".join(random.choice(joke)),
            center=(450, 300),
            fontname="rabbit_on_the_moon",
            fontsize=36,
            color="darkorange1",
            owidth=1.5,
            ocolor="black"
        )
        play_sound = random.choice(funny_sound)
        play_sound.play()
        reset_button.draw()

def on_mouse_down(pos, button):
    """
    click a button to select a joke category
    """
    global joke
    if button == mouse.LEFT and buttons[0].collidepoint(pos):
        joke = animal_jokes

    elif button == mouse.LEFT and buttons[1].collidepoint(pos):
        joke = food_jokes

    elif button == mouse.LEFT and buttons[2].collidepoint(pos):
        joke = silly_jokes

    elif button == mouse.LEFT and buttons[3].collidepoint(pos):
        joke = school_jokes

    elif button == mouse.LEFT and reset_button.collidepoint(pos):
        joke = ""

Joke_Generator_User_Guide.pdf

Joke_Generator_User_Guide.docx


ntoll Nicholas Tollervey ~ 11 Jan 2023 4:01 p.m.

Hi Paul,

I think I have enough evidence to be able to write up an assessment. This is a three step process:

  1. I write up my assessment.
  2. A third party checks it, points out corrections or advises on ways I can improve my feedback to you.
  3. Once the review is approved in step 2, you get your results.

I think you should get your results over the weekend or at the start of next week. 🚀


honeyp Paul Honey ~ 18 Jan 2023 3:44 a.m. (updated: 18 Jan 2023 3:47 a.m.)

The Final Product

The below video gives a quick demonstration of the generator in action, with a quick scroll through the code at the start.

The Random Joke Generator


Back to top