EXERCISE 19: Add view history option

Task 1: Write a function called get_progress_history() which gets previously stored score data from progress.txt and returns a list of the data in each line.

The function should read in the data from progress.txt line by line, using the separator to capture each variable, and add it to the list that will be returned, e.g. [(10, 20.0), (10, 50.0)]. If the progress.txt file is not found or there is no score data stored, an empty list should be returned.

Task 2: Add a new menu option to view progress history and print out data from the previous sessions.

When the user selects the menu option to view progress history, the get_progress_history() function should be called to get a list containing the score data from progress.txt.

Add logic and formatting to display the history in a user-friendly way, e.g.

10 cards completed, score 60% 
10 cards completed, score 90% 
10 cards completed, score 70% 

Bonus Task: Allow the user to set the number and order of sessions they want to view in their history with a dialog, e.g. Ask about the number first

How many sessions would you like to view?
Enter the number or 0 to show all

Then the order

What order would you like to see them in?
1: Oldest 
2: Most recent

You might want to revisit how to slice lists. And remember that you will have to index the list of rows in reverse to get data for the most recent sessions.

Run and check: Run your code in the terminal to make sure it works with the command

python flashcards_app`
  • Do a few flashcard sessions.
  • Select the option to view your progress history.
  • You should your progress history message with each session’s scores.
  • Close and restart the program - your history should still be there.
  • Check your progress.txt file to see if the values have been saved correctly.

Read through and add comments: Add any comments in your code that will help you understand it when you come back to it later.

Save your progress: Commit with message “EXERCISE 19: Add view history option” and save your work to Github with the standard Git workflow.

(Re)read the guides:

Example solution

flashcards_app.py

# Created by: Alex Ubuntu
# Date: 01.01.2026
# Purpose: A personal flashcard trainer to help with learning

# Import the random module
import random

### LOAD FLASHCARDS
# Set flashcards list from file
# Initialize empty list
flashcards_list = []
file_separator = ','

# Open and read the file
flashcard_file = "flashcards.txt"
try:
    with open(flashcard_file, 'r') as file:
        lines = file.readlines()
except:
    # Handle scenario where file is not found 
    # and display comprehensible message to user.
    print(f"The file {flashcard_file} is missing. Please add it to initialise your flashcards.")
    exit()

# Process each line
# Each line has: question,answer
for line in lines:
    # Remove whitespace/newlines
    line = line.strip()
    
    # Extract question and answer 
    # with pattern matching assuming two comma
    # separated values in a row:
    question, answer = line.split(file_separator)
    
    # Add to list
    flashcards_list.append((question, answer))

# Confirm loaded
print(f"{len(flashcards_list)} flashcards loaded!")

### INITIAL INTERACTION WITH USER
# Welcome message
print("Welcome to your personal flashcard trainer!")

# Absolute maximum number of cards so that the user can't ask for too many
ABSOLUTE_MAX_CARDS = 100
DEFAULT_MAX_CARDS = 20

# Fetch from user and save to variable
name = input("What is your name? ")
max_cards = DEFAULT_MAX_CARDS # Set a default value for max_cards

# Confirm name
print(f"\nMy name is {name}")

# Card and score variables
num_cards_completed = 0
num_cards_correct = 0
score = 0

### FUNCTIONS
# Function to calculate and display score information
def display_score_info():

    # Handle case where no cards have been completed yet.
    if num_cards_completed <=0:
        print("You need to practice before you can get a score.")
    else:
        # Calculate score
        score = (num_cards_correct/num_cards_completed) * 100
        print(f"\nYou have answered {num_cards_correct} out of {num_cards_completed} correctly. Your score is {score}%.")

# Function to write score information to file
def write_score_info():
    # Calculate score
    score = (num_cards_correct/num_cards_completed) * 100
    # Open the file
    with open('progress.txt', 'a') as file:
        # Write score information and new line so next entry appears on
        # row below
        file.write(f"{num_cards_completed},{num_cards_correct},{score}\n")

### APP MENU LOOP
while True:
    print("\nSelect an option by entering a number")
    print("1: Set the number of cards you wish to practice")
    print("2: Start flashcards")
    print("3: Show the current score")
    print("4: View progress history") # Option to view progress history
    print("5: Exit")
    
    
    choice = input("\nChoose an option: ")
    
    if choice == "1":

        while True:
            # More stringent validation for input for maximum number of cards
            
            # Fetch input from user but don't attempt to convert the input string 
            # to int until certain it will work 
            entered_max_cards = input("\nHow many cards would you like to practice each session? ")

            # Check if input string represents an integer
            if entered_max_cards.isdigit():

                # Convert to integer data type
                entered_max_cards = int(entered_max_cards)
            
                # Check if value is within the value range 
                # (between 1 and the absolute maximum number of cards)
                if entered_max_cards > 0 and entered_max_cards < ABSOLUTE_MAX_CARDS:
                    
                    # Set the max_cards variable with the user's preference
                    max_cards = entered_max_cards
                    # Confirm number maximum number of cards per session
                    print(f"\nI want to practice at most {max_cards} cards per session")
                    break
                else:
                    ## Let the user know what the range should be (Bonus task).
                    print(f"\nPlease enter a valid number bewteen 1 and {ABSOLUTE_MAX_CARDS}.")    
            else:
                print(f"\nPlease enter a whole number number over 0.")

            

    elif choice == "2":
        
        # Reset the number of cards completed and correct for each session
        num_cards_completed = 0
        num_cards_correct = 0
        
        # Shuffle the flashcards list
        random.shuffle(flashcards_list)
        
        # Using a for loop means that the number of flashcards displayed
        # is limited by the number of items in flashcards so the user
        # may end up practicing fewer cards than they specified  
        for q, a in flashcards_list:
            # Ask user question and save response into variable
            user_answer = input(f"\nQuestion: {q}\n")
            
            # Increment the count of cards completed
            num_cards_completed += 1
            
            # Display user's answer and correct answer
            print(f"Your answer: {user_answer}, Correct answer: {a}")

            # Response deemed to be correct even if given in different case
            if user_answer.lower() == a.lower():
                
                # Increment count of cards answered correctly
                num_cards_correct += 1
                print("Correct")
            else:
                print("Incorrect")
            
            # Check if number of cards completed has hit the user's
            # preferred maximum number of cards
            if num_cards_completed >= max_cards:
                
                break
        
        print("\nWell done on completing your practice session!")
        # Write score info out with each session completed
        write_score_info()
        display_score_info()

    elif choice == "3":

        display_score_info()

    elif choice == "4":
        #Session 4: 10 cards completed, score 60% 
        # Open and read the file
        with open('progress.txt', 'r') as file:
            lines = file.readlines()

        # Process each line
        # Each line has: num_cards_completed,num_cards_correct,score
        # Enumerate to get the session number - assumes the 
        # row number corresponds to the session number
        for i, line in enumerate(lines):
            # Remove whitespace/newlines
            line = line.strip()
    
            # Split by ',' separator
            parts = line.split(file_separator)


            # Extract num_cards_completed,num_cards_correct,score
            # Name these variables something different 
            # (e.g. saved_cards_completed, saved_cards_correct, saved_score) 
            # so they don't write over those being used by the rest of the program
            saved_cards_completed = parts[0]
            saved_cards_correct = parts[1]
            saved_score = parts[2]

            print(f"Session {i}: {saved_cards_completed} cards completed, score {saved_score}%")

    elif choice == "5":
        print(f"We hope you enjoyed your practice session today, {name}.")
        
        display_score_info()

        # Display feedback message based on score
        if score > 90 and score <= 100:
            print("Excellent work!")
        elif score > 70 and score <= 90:
            print("Good job!")
        elif score > 50 and score <= 70:
            print("Keep practicing!")
        elif score > 0 and score <= 50: 
            print("Need more study time!")
        
        print("Look forward to seeing you again soon!")
        break
    
    else:
        # Clarify instruction to get valid input
        print("\nInvalid value entered. Please make sure you enter just a single digit (no other words): 1, 2, 3 or 4, to select an option.")

With an additional dialog to ask for number and order of sessions to include (Bonus Task)

# Created by: Alex Ubuntu
# Date: 01.01.2026
# Purpose: A personal flashcard trainer to help with learning

# Import the random module
import random

# Welcome message
print("Welcome to your personal flashcard trainer!")

# Fetch from user and save to variable
name = input("What is your name? ")
max_cards = 20 # Set a default value for max_cards

# Confirm name
print(f"\nMy name is {name}")

# Card and score variables
num_cards_completed = 0
num_cards_correct = 0
score = 0

# Set absolute maximum number of cards so that the user can't ask for too many
ABSOLUTE_MAX_CARDS = 100

# Set flashcards dictionary from file
# Initialize empty dictionary
flashcards = {}
file_separator = ','

# Open and read the file
with open('flashcards.txt', 'r') as file:
    lines = file.readlines()

# Process each line
# Each line has: question,answer
for line in lines:
    # Remove whitespace/newlines
    line = line.strip()
    
    # Split by ',' separator
    parts = line.split(file_separator)
    
    # Extract question and answer
    question = parts[0]
    answer = parts[1]
    
    # Add to dictionary
    flashcards[question] = answer

# Confirm loaded
print(f"{len(flashcards)} flashcards loaded!")

# Function to calculate and display score information
def display_score_info():

    # Handle case where no cards have been completed yet.
    if num_cards_completed <=0:
        print("You need to practice before you can get a score.")
    else:
        # Calculate score
        score = (num_cards_correct/num_cards_completed) * 100
        print(f"\nYou have answered {num_cards_correct} out of {num_cards_completed} correctly. Your score is {score}%.")

# Function to write score information to file
def write_score_info():
    # Calculate score
    score = (num_cards_correct/num_cards_completed) * 100
    # Open the file
    with open('progress.txt', 'a') as file:
        # Write score information and new line so next entry appears on
        # row below
        file.write(f"{num_cards_completed},{num_cards_correct},{score}\n")

while True:
    print("\nSelect an option by entering a number")
    print("1: Set the number of cards you wish to practice")
    print("2: Start flashcards")
    print("3: Show the current score")
    print("4: View progress history") # Option to view progress history
    print("5: Exit")
    
    
    choice = input("\nChoose an option: ")
    
    if choice == "1":

        while True:
            # More stringent validation for input for maximum number of cards
            
            # Fetch input from user but don't attempt to convert the input string 
            # to int until certain it will work 
            entered_max_cards = input("\nHow many cards would you like to practice each session? ")

            # Check if input string represents an integer
            if entered_max_cards.isdigit():

                # Convert to integer data type
                entered_max_cards = int(entered_max_cards)
            
                # Check if value is within the value range 
                # (between 1 and the absolute maximum number of cards)
                if entered_max_cards > 0 and entered_max_cards < ABSOLUTE_MAX_CARDS:
                    
                    # Set the max_cards variable with the user's preference
                    max_cards = entered_max_cards
                    # Confirm number maximum number of cards per session
                    print(f"\nI want to practice at most {max_cards} cards per session")
                    break
                else:
                    ## Let the user know what the range should be (Bonus task).
                    print(f"\nPlease enter a valid number bewteen 1 and {ABSOLUTE_MAX_CARDS}.")    
            else:
                print(f"\nPlease enter a whole number number over 0.")

    elif choice == "2":

        # Reset the number of cards completed for each session
        num_cards_completed = 0
        num_cards_correct = 0

        # Iterate through flashcards list of tuples
        # Each tuple element of the list contains a question, answer pair
        # Using a for loop means that the number of flashcards displayed
        # is limited by the number of items in flashcards so the user
        # may end up practicing fewer cards than they specified  
        for q, a in flashcards_list:
            # Ask user question and save response into variable
            user_answer = input(f"\nQuestion: {q}\n")
            
            # Increment the count of cards completed
            num_cards_completed += 1
            
            # Display user's answer and correct answer
            print(f"Your answer: {user_answer}, Correct answer: {a}")

            # Response deemed to be correct even if given in different case
            if user_answer.lower() == a.lower():
                
                # Increment count of cards answered correctly
                num_cards_correct += 1
                print("Correct")
            else:
                print("Incorrect")
        
            # Check if number of cards completed has hit the user's
            # preferred maximum number of cards
            if num_cards_completed >= max_cards:
                break
        
        print("\nWell done on completing your practice session!")
        # Write score info out with each session completed
        write_score_info()
        # Display score info at the end of a session
        display_score_info()

    elif choice == "3":

        display_score_info()

    elif choice == "4":
        #Session 4: 10 cards completed, score 60% 
        # Open and read the file
        with open('progress.txt', 'r') as file:
            lines = file.readlines()

        print("How many sessions would you like to view?")
        num_sessions = int(input("Enter the number or 0 to show all: "))
        print("What order would you like to see them in?")
        print("1: Oldest")
        print("2: Most recent")
        order = input("Choose an option by entering 1 or 2: ")

        # If the user wants to see all sessions, set num_sessions
        # to the number of sessions available
        if num_sessions==0:
            num_sessions = len(lines) 

        selected_lines = lines
        if order =="2":
            # Need to reverse order of list if 
            # most recent first is selected
            selected_lines = selected_lines[::-1]
        selected_lines = selected_lines[:num_sessions]
        
        #TODO: Add handling of invalid inputs

        # Process each line
        # Each line has: num_cards_completed,num_cards_correct,score
        # Enumerate to get the session number - assumes the 
        # row number corresponds to the session number
        for i, line in enumerate(selected_lines):
            # Remove whitespace/newlines
            line = line.strip()
    
            # Split by ',' separator
            parts = line.split(file_separator)

            # Extract num_cards_completed,num_cards_correct,score
            # Name these variables something different 
            # (e.g. saved_cards_completed, saved_cards_correct, saved_score) 
            # so they don't write over those being used by the rest of the program
            saved_cards_completed = parts[0]
            saved_cards_correct = parts[1]
            saved_score = parts[2]

            print(f"Session {i}: {saved_cards_completed} cards completed, score {saved_score}%")

    elif choice == "5":
        print(f"We hope you enjoyed your practice session today, {name}.")
        
        display_score_info()

        # Display feedback message based on score
        if score > 90 and score <= 100:
            print("Excellent work!")
        elif score > 70 and score <= 90:
            print("Good job!")
        elif score > 50 and score <= 70:
            print("Keep practicing!")
        elif score > 0 and score <= 50: 
            print("Need more study time!")
        
        print("Look forward to seeing you again soon!")
        break
    
    else:
        # Clarify instruction to get valid input
        print("\nInvalid value entered. Please make sure you enter just a single digit (no other words): 1, 2, 3 or 4, to select an option.")

Take a break: 🧘