Software Design and Development – Assignment 1

Python Script

#!/usr/bin/python3
# the above line is a shebang for Linux systems, making the script executable

# import the required libraries
import random

# using a class essentially allows for grouped, named variables
class output_colours:
    normal      = "\033[m"
    incorrect   = "\033[91m"
    correct     = "\033[92m"
    warning     = "\033[93m"
    emphasis    = "\033[94m"

# ask the user for their name, and say hello
# the title() method makes sure the first letter is upper-case
name    = input(output_colours.emphasis + "\nWhat's your name? " + output_colours.normal).title()
print("Hello, " + name + "!")

def run_quiz():

    # initialise a variable to count correct answers
    count_correct   = 0

    # execute the question section five times
    # although i isn't needed, it does improve the user experience ("question i of 5")
    for i in range(1, 6):

        # generate two random numbers in an array, and find their product
        numbers = [
            random.randint(1,21),
            random.randint(1,21)
        ]
        product = numbers[0] * numbers[1]


        # introduce question
        print("\nQuestion " + output_colours.emphasis + str(i) + output_colours.normal + " of 5:")

        # the question has yet to be answered with a valid answer (correctness irrelevant)
        answered    = False

        while not answered:

            # an "x" is used rather than a "*" as not everyone is familiar with the latter
            answer  = input("What is " + str(numbers[0]) + " x " + str(numbers[1]) + "? ")

            # try to convert answer to an integer
            try:
                answer  = int(answer)

            # if they didn't give a valid numeric answer
            except ValueError:
                print(output_colours.warning +
                    "That answer doesn't seem to be a whole number." +
                    "Please give your answer as digits, such as \"45\"." +
                    output_colours.normal)

            # if everything goes well
            else:
                answered    = True

        # compare the user's answer with the real product
        # if the answer was right:
        if answer == product:
            # congratulate and increase count_correct by one
            print(output_colours.correct + "Correct!" + output_colours.normal + " Well done!")
            count_correct  += 1

        # if the answer was wrong:
        else:
            # tell them the correct answer
            print(output_colours.incorrect +
                "Sorry; that wasn't correct." +
                output_colours.normal +
                " The answer is actually " +
                output_colours.emphasis +
                str(product) +
                output_colours.normal)

    # initialise comment variable
    # this holds a string with a comment about the user's score
    comment     = ""
    if count_correct == 5:
        comment = "Perfect!"
    elif count_correct == 4:
        comment = "Almost 100%. Good job!"
    elif count_correct == 3:
        comment = "Not bad!"
    elif count_correct == 2:
        comment = "Could be worse."
    elif count_correct == 1:
        comment = "At least you got one right!"
    elif count_correct == 0:
        comment = "Better luck next time."

    # tell the user what score they reached
    print("\nWell, " +
        name +
        ", you scored " +
        output_colours.emphasis +
        str(count_correct) +
        output_colours.normal +
        "/5. " +
        comment)

    # ask the user if they would like to run the quiz again
    try_again   = input("Would you like to have another go? [" +
        output_colours.correct +
        "Y" +
        output_colours.normal +
        "/" +
        output_colours.incorrect +
        "N" +
        output_colours.normal +
        "] ")
    if try_again.upper() == "Y":
        run_quiz()

# run the quiz
# up until this point it has merely been defined in a function, and must be called
run_quiz()

# bid farewell before quitting
print(output_colours.emphasis + "\nBye!" + output_colours.normal)

Variables and Data Types [P4]

Variables I Created

In the script that I have written, a number of different variables are created. Created at different points in the program, they assume different levels of scope. The place in which the variables are declared defines this scope, which ensures there are no conflicts when repeating blocks of code or calling functions several times.

Before the main function is defined, I declare six variables; all of which are strings. The first five appear in the output_colours class, and are used to change the colour of output text. Although this is not essential, it provides the user with a better experience. The last variable is the name string. This holds user input collected from the console, once converted to the right case using the .title() method.

Inside of the run_quiz() function, more variables are declared. The first is count_correct, which is an integer that holds the number of questions that the user answered correctly. Each time the user submits the correct answer to one of the questions, this variable's value is increased by one using the += operator.

The script then enters a for loop. Immediately three variables are declared: numbers, an array of integers; product, an single integer; and answered, a Boolean. The first consists of two numbers, generated using the randint() function from the random module. They each assume different values between one and twenty, inclusive. The second variable is found by multiplying the two number generated for the numbers array. This is the answer that the script looks for later. Thirdly, the Boolean variable is set to False, which is inverted once a valid answer has been given (for example, "5", as opposed to "five").

The script then enters a try..except block, which attempts to convert the value entered by the user to an integer. If this fails due to a ValueError, almost certainly caused by the user not inputting an answer as numerical digits, the script will ask the question a second time. In order to test whether or not the answer can be converted, the answer variable is passed to the int() function, which raises and exception if it cannot. If the answer successfully converts, the answered variable is set tot True so that the while loop started beforehand stops.

After this, the answer given, now in integer form, is compared to the actual answer, held in the product variable. If the two variables are equal, if answer == product, the count_correct variable is increased by one, as mentioned before. Once all five questions have been answered, the script exits the for loop started near the beginning of the run_quiz() function.

An empty string variable is created called comment, which is then modified based on the score achieved in the quiz. It must be declared outside of the if..elif block so that the variable is still available to code after the block.This is an example of variable scope.

After this point, only one more variable is declared; try_again. This is filled with text input from the user. If the user enters "y" or "Y", the quiz will run again, otherwise the script will exit.

Uses of Data Types

Although different programming languages have different syntax and ways of declaring variables, the underlying, fundamental variable types exist in almost all languages. These are some of the most common.

An important aspect of being a programmer is to be able to judge what type of variable would be best suited for storing a particular piece of information. Below are some types of data that a program may need to store, and which data types I would use for them.

Structures of Programming [P3]

Although many different programming languages exist, and they almost all have different syntactic patterns, the fundamental building blocks of programming exist in most, if not all, of them.

Selections and Conditionals

In order to execute part of a program only if a particular condition is met, conditionals are used. These appear in a number of places, but their most basic use is generally in an if statement. Consider the following snippet of Python code:

input_number    = int(input("Enter an integer: "))

if input_number == 5:
    print("Five was entered.")
elif input_number > 10:
    print("A number greater than 10 was entered.")
else:
    print("A number below 11, which wasn't 5, was entered.")

Here, the user is asked to input an integer. Once data has been received, it is converted to an actual integer, as the input() function returns a string. Once an integer, the input_number variable is easier to compare.

The first clause of the if..elif..else block compares the answer with the number 5. If the two are equal (i.e., the user entered 5) the program outputs a string using the print() function.

The second clause of the block uses a different operator. Rather than == (is equal to) it uses > (is greater than), meaning that the conditional will equate to true if the user-generated integer is greater than 10. It's also worth noting that the line begins with elif (else if) rather than if. This means that the conditional will only be evaluated if the first conditional equated to false. I utilised this fact in the program I wrote close to the end, when picking a comment to print. Although the users score could easily match several of the conditionals I used, the interpreter leaves the if block once one of the conditions has been met.

The third clause of the block begins with else, meaning that the code found in that section will only the executed if none of the conditions above equated to true. This is useful for creating a fall-back value for a variable, if none of a series of conditions are met.

Functions/Sequences

In order to avoid the repetition of a particular section of code, which is inefficient, and to make code more maintainable and easier to debug, programmers use functions or sequences of operations. These are essentially blocks of code that have been removed from the main part of the program, and been given a name. This means that at different points in the program, the section can be called, and will be executed, before the program continues.

By splitting parts of a program into functions that accept arguments, a program can become much easier to develop and manage. The following is an example of the definition of a simple function in Python, which takes two arguments and returns the result of their multiplication, plus one.

def foo(number_1, number_2):
    return number_1 * numner_2 + 1

print(str(foo(2, 10)))
print(str(foo(5, 6)))

The program begins by defining the foo() function. The two variables it accepts are given names, which are only effective within the function's code. The one line inside the function returns an integer, found by multiplying the two arguments given to it using the * operator, and then adding 1.

After the function is defined, it's used in a print function call. The foo() function is called, and passed the integers 2 and 10 as arguments. The output of the function, 21 as an integer, is then piped through the str() function, which converts the integer value to a string. This is what the print() function receives, and shows to the user.

The last line then does the same as the one before it, but passes 5 and 6 to the foo() function. This would result in the program outputting 31 after 21. By using a function in this scenario, the code is made more maintainable and less repetitive. If the developer was to decide that they would rather the foo() function would rather add 5 where it currently adds 1, only one line would need to be changed. Had a function not been used, 2 would need to be.

Iterations and Loops

In order to repeat a section of code a number of times with a minor difference and in immediate succession, a loop is typically used. Below the for loop is explained.

The for loop is generally given three pieces of code, which are executed or evaluated at different points. In JavaScript, for example, a typical loop looks roughly like this:

for (var i = 0; i < 10; i++) {
    ...
}

The first of the three pieces of code is executed once at the beginning of the loop. This is generally used to create a variable to count the number of times the loop has been executed. The second piece is a conditional that is evaluated every time the loop runs. If this conditional equates to true, the code inside the loop will be executed, otherwise the program will continue to run after the loop's closing wiggly-brace (}). The third piece of code is executed every time the conditional is evaluated to true.

In this case, a variable is created, i, and set to a value of 0. Each time the loop is attempted, the interpreter will check whether or not the variable i is less than 10. If it is, the loop will run. Lastly, the variable i is increased by one, so that the loop does not execute indefinitely.