Make a super heroes quiz with python (Part 1)

Hello everybody, what's up? Every pleasure to meet you and write, together, some goods scripts, which can be help to solve some needs. Today, script we'll write will be some fun. Indeed, we'll realize a quiz. This quiz is little bit particular. I explain myself. Firstly, i want precise you that if you're superheroes fan, you'll love this script!

What will we do in this script? That is the question... πŸ€”

question.png

At Scripting Day, we like explicit things. So we need to define how the process of this quiz. Good! Let's go.

  • We choose an heroes team (Marvel, DC comics or Hyper heroes)
  • Some questions which refers to team chosen will be asked. We'll must answer to it
  • At end, we get a score
  • Then, a random book will be create and store in a folder. Book content will be:
    • cover page (an heroe picture, who belongs to our heroes choice team)
    • our name and answers, with quiz correction
    • heroe story (who is on cover page)
    • two or three heroes pictures who belongs to our heroe team choice

Obviously, each script we code need some prerequisites! So, let's list them.

Prerequisites

quiz.jpg

To code this script, we must have some knowledge such as:

  • list and dictionary use
  • files path handling (here, we'll use pathlib module, but you're free to use os module)
  • csv module use (for creating and reading csv file)
  • pdf file handling (we must install PyPDF2 and reportlab)

Here are some documentation for prerequisites:

Ready? Good, let's code our app now!!!

Firstly, create a folder called heroes_stories. All our script, files and folders will be inside it.

alpha@alpha:~$ mkdir heroes_stories && cd heroes_stories

Heroes list

For our quiz, we will define three teams of heroes. As a result, we will create three lists (each list for a hero team). Our heroes team are:

  • marvel team
  • Hyper team
  • Dc Comics team

Each category will store the images of its heroes (as a pdf file). Let's create a folder containing these images (one folder for each team).

alpha@alpha:~/heroes_stories$ mkdir Heroes && cd Heroes
alpha@alpha:~/heroes_stories/Heroes$ mkdir dc_comic hyper marvel

Inside theses folders, put correct heroes pictures.

You can download heroes pictures here.

Now we've our heroes pictures, we need to code functions which we'll use to interact with its files (heroes pictures) in our application. We'll code into a file called heroes_list.py (create it).

alpha@alpha:~/heroes_stories$ touch heroes_list.py

Inside it, firstly, import pathlib and randint, then let's precise heroes files path.

heroes_list.py

import pathlib
from random import randint

# Heroes path
the_path = pathlib.Path.cwd() / 'Heroes'

# Specific heroes path
dc_heroes_path = the_path / 'dc_comic' # Folder where DC Comics heroes are
marvel_heroes_path = the_path / 'marvel' # Folder where Marvel heroes are
hyper_heroes_path = the_path / 'hyper' # Folder where hyper heroes are

To permit user to choose a super heroe, he must see their name! So it's obvious that we must display them to user. So how can we do it? 1rst thing we know is folders where they stored. So we need to find a way to list them and display them in order to permit user to choose one of them. We can just write their name! Yes, but if later, we want to add other heroes in folders, it'll be fastidious to add manually their names. So we must need to write a generic code which be able to display automatically names of super heroes, even if we add other names later. How then get the list of superheroes that are in folders and display them to the user? One way will be to display each file within the hero folders to get the name of the hero, while taking care to remove the file extension.

heroes_list.py

dc_heroes_list = []
marvel_heroes_list = []
hyper_heroes_list = []

# Let's define a function which take a path and list in which fill out
# heroes name
def fill_out_heroes_name(path, the_list):
    """ Take a path.
    In this path, get all files which can be found.
    Next, for each file, get only the name without extension, and fill out
    the list which passed in arguments with these names.
    """

    # 1rst method
    for the in path.rglob('*'):
        the_name = the.stem # get the name of file without it's extension
        the_list.append(the_name) # fill out the list


    '''Another method: using os module (2nd method)
    As we know that all files have same extension (.pdf), we could procceded
    by use listdir method (os module) firstly and then, remove the extension
    by removing 4 last character of each file name.

    the_files = os.listdir(path) # get all files which can be found
    for names in the_files:
        the_name = names[:-4] # get the name of file without it's extension
        the_list.append(the_name)
    '''

    return the_list

def fill_on_number(team_number):
    """Get team number and fill out correct list """

    #NOTE: team number based on main scenario in heroes.py

    if team_number == 1:
        heroes_team = fill_out_heroes_name(dc_heroes_path, dc_heroes_list)
    elif team_number == 2:
        heroes_team = fill_out_heroes_name(hyper_heroes_path, hyper_heroes_list)
    else:
        heroes_team = fill_out_heroes_name(marvel_heroes_path, marvel_heroes_list)

    return heroes_team

If you prefer os module instead of pathlib, you can use 2nd method and comment the 1rst. In addition, we don't create heroes.py file yet. We'll do it in next part.

Our first function (fill_out_heroes_name) take as arguments, the heroes folder path and heroes list in which heroes names must be added. Then, for each heroes pictures which is in folder path specified, it add the name (without extension) in list. In our application, we'll ask user to choose team he wants. Then, according to team number he'll chosen, function will execute 1rst function and save the result in variable called heroes_team, then return this variable.

For bonus pictures, it would cool to create a function which choose randomly two or three heroes pictures which will be add to generated book, isn't it? If you're agree with me, let's code it!

def choose_bonus_picture(heroes_list):
    """ Get a list a return two or three heroe in this list """

    # choose if we want get two or three heroes pictures as bonus
    bonus_heroes_number = randint(2, 3)

    heroes = []

    for x in range(0, bonus_heroes_number):
        heroes_list_length = len(heroes_list)

        the_heroe_name = heroes_list[randint(0, heroes_list_length-1)]

        while the_heroe_name in heroes:
             the_heroe_name = heroes_list[randint(0, heroes_list_length-1)]

        heroes.append(the_heroe_name)

    return heroes

We created a function for bonus picture, but what's about cover picture!

def choose_cover_page(heroes_list):
    """Choose in a list one heroe for cover page"""

    choosen_num = randint(0, len(heroes_list)-1)

    return heroes_list[choosen_num]

We have finished the heroes_list.py file script. Now, what is the next task? Remember, in our application, we want that after answering questions, a book is generated for the user. It is now time to code the script that will do it! πŸ‘ πŸ‘Š

The generated book

Here, we'll write scripts which permit us to create book for player. As remember, book will contains:

  • Cover page made with an heroe (choosen randomly) from team choosen by player
  • Player name and his score
  • Biography of heroe which is on cover page
  • Two or three heroes pictures as bonus

Let's start by import.

book.py

import pathlib
from PyPDF2 import PdfFileReader, PdfFileWriter
from reportlab.pdfgen import canvas
import heroes_list

NB: you'll need to install PyPDF2 and reportlab

alpha@alpha:~/heroes_stories$ pip3 install reportlab
alpha@alpha:~/heroes_stories$ pip3 install PyPDF2

Generated books will be store in a folder called Edited_books (so, create it). Create another folder called trash_pdf. Now, let's create function which will generate book.

caution.jpg

To understand this function, i recommend you to be familiar to with files and path handling.

Instead comment each code in this function directly here, i added comments directly in function.

book.py

def conceive_book(player_name, heroe_team, cover_heroe, player_score,
                  quiz_summary, bonus_pictures):

    """Use arguments to create a pdf book"""

    the_heroes_path = pathlib.Path.cwd() / f'{heroe_team}'
    bonus_pictures_names = [] # use list to collect bonus pictures

    # define generated book name (with its extension)
    output_file_name = pathlib.Path.cwd() / 'Edited_books' / f'quiz result of {player_name}.pdf'
    output_file = open(output_file_name, 'wb')

    output_pdf = PdfFileWriter()

    # Introduction text with player name
    intro_text = f'Mega heroes quizz with {player_name}'

    # The cover page
    cover_page_name = the_heroes_path / f'{cover_heroe}'
    cover_page = PdfFileReader(open(cover_page_name, 'rb'))

    # store player score into a variable
    display_score = f'Score: {player_score}/20 | {player_score*100 / 20}%'

    # Create book
    output_pdf.addPage(cover_page.getPage(0)) # add cover page

    ''' For add some pages, i'll need to create them and then, 
    add them to final pdf file. These files will be at "trash_pdf" folder.
    '''

    # let's create a pdf page which will store intro text and player score
    trash_path = pathlib.Path.cwd() / 'trash_pdf'
    intro_path = trash_path / 'intro.pdf'
    intro_pdf = canvas.Canvas(f'{intro_path}')
    intro_pdf.setFont('Helvetica', 28)
    intro_pdf.drawString(50, 500, f'{intro_text}')
    intro_pdf.setFont('Helvetica', 18)
    intro_pdf.drawString(200, 450, f'{display_score}')
    intro_pdf.save()

    intro_file = PdfFileReader(open(intro_path, 'rb'))
    output_pdf.addPage(intro_file.getPage(0))

    # add quiz summary
    quiz_summary_path = trash_path / 'quiz_summary.pdf'
    quiz_summary_pdf = canvas.Canvas(f'{quiz_summary_path}')
    quiz_summary_pdf.setFont('Helvetica', 28) # set title font
    quiz_summary_pdf.drawString(180, 700, 'Quiz summary') # write title
    quiz_summary_pdf.setFont('Helvetica', 11) # set font for other lines
    line_height_level = 600
    i = 1
    for key_value, info_value in quiz_summary.items():
        quiz_summary_pdf.drawString(10, line_height_level, f'{key_value} {info_value}')

        if i % 2 == 0:
            line_height_level -= 50
        else:
            line_height_level -= 20

        i += 1
    quiz_summary_pdf.save()

    quiz_summary_file = PdfFileReader(open(quiz_summary_path, 'rb'))
    output_pdf.addPage(quiz_summary_file.getPage(0))

    # add bonus pictures
    for picture in bonus_pictures:
        picture_file_name = the_heroes_path / f'{picture}.pdf'
        picture_file = PdfFileReader(open(picture_file_name, 'rb'))
        output_pdf.addPage(picture_file.getPage(0))

    output_pdf.write(output_file) # write all output_pdf content in output_file
    output_file.close()

hourra.jpeg

Good done!!! We finished this first part !!! In the next part, we'll add questions, a scenario and other fun things. So stay tuned and I wish you a nice Sunday!!!

end.jpg

No Comments Yet