Building a quiz with a time limit in python and golang

In this article, I am going to go through how we might create a terminal based quiz application where we ingest a CSV with quiz questions and answers, accept an answer from a user (and confirm if it’s correct) while doing a countdown to make sure they don”t exceed a specified time limit.

In the main function, I have made a call to the extract() and the quizme() functions. Let’s first look at extract.

So, what are we doing here. Well, we’re creating a function called extract, which has a return type of slice of strings. So, the idea is, each row of the CSV will become an entry in the slice.

We then define where the quiz file is and open it using the ioutil package. As you’ll know if you’ve worked with this package before, it comes out as a byte slice, so we convert that to be a string value.

Finally, we split the contents at each new line. The output of the split function is a slice of strings. We then return that.

func extract() []string {
	//define filepath
	filepath := "quiz.csv"

	//open the file
	openfile, _ := ioutil.ReadFile(filepath)

	//cast byte slice as string
	contents := string(openfile)
	s := strings.Split(contents, "\n")

	return s
}

Now, back to the main function, we pass the returned value (s) to the quiz me function. So, in that function, as you can see below, we ingest s (which is a slice of strings). We then create a couple of variables, which we’ll increment in the loop: the first, is the question number, so we can tell the user how many questions they answered and the other is a counter for how many of those questions they got correct.

We then create a new timer. That timer has a duration set of 3 (which is 3 seconds, for testing purposes) and we multiply that by time.Second to make it an actual second value.

In the loop, we split the string. Why? Because each line of the CSV like like this: 4+5, 9, where 4+5 is the question the user needs to answer and 9 is the correct outcome. So, by splitting at the comma, the first split is the question and the second split is the answer.

Of course, this is a slice of strings, so we need to convert the answer to integer, so we can make a comparison against the user entered answer.

Next, we create a select case statement where we say ‘If the channel has reported the timer is out of time’, then we exit the process, otherwise we take the user input and compare that against the correct answer. In both situations, we increment the question count and the correct count.

func quizme(s []string) {
question_number := 0
correct := 0
timer := time.NewTimer(time.Duration(3) * time.Second)

for _, value := range s {
    //extract the question and answer 
    fmt.Println("loop start")
    question := strings.Split(value, ",")[0]
    answer := strings.Split(value, ",")[1]
    //convert string to int
    answer2, _ := strconv.Atoi(answer)

    //SELECT CASE STATEMENT 
    select {
    //If the channel has reported timer is out of time then return
    case <- timer.C:
    fmt.Println("you got this many questions correct")
    fmt.Println(correct)
    fmt.Println(question_number)
    return
    default :
    //Show the user the question
    fmt.Print("Question: " + question)

    //create variable i (short for input)
    var i int
    _, err := fmt.Scanln(&i) //request user input in terminal

    //check whether user input is correct or not
    if i == answer2 {
        correct = correct + 1
        question_number = question_number + 1
        fmt.Println("CORRECT")
        } else {
        fmt.Println("INCORRECT", err)
        question_number = question_number + 1
        }
    }
}
fmt.Println("you got this many questions correct")
fmt.Println(correct)
fmt.Println(question_number)
}

Full GO Code:

package main

import "fmt"
import "io/ioutil"
import "strings"
import "strconv"
import "time"

//https://tour.golang.org/concurrency/5

func main () {
	s := extract()
	quizme(s)
}

func extract() []string {
	//define filepath
	filepath := "quiz.csv"

	//open the file
	openfile, _ := ioutil.ReadFile(filepath)

	//cast byte slice as string
	contents := string(openfile)
	s := strings.Split(contents, "\n")

	return s
}

func quizme(s []string) {
	question_number := 0
	correct := 0
	timer := time.NewTimer(time.Duration(3) * time.Second)

	for _, value := range s {
		//extract the question and answer 
		fmt.Println("loop start")
		question := strings.Split(value, ",")[0]
		answer := strings.Split(value, ",")[1]
		//convert string to int
		answer2, _ := strconv.Atoi(answer)
		
		//SELECT CASE STATEMENT 
		select {
		//If the channel has reported timer is out of time then return
		case <- timer.C:
		fmt.Println("you got this many questions correct")
	    fmt.Println(correct)
		fmt.Println(question_number)
		return
		default :
		//Show the user the question
		fmt.Print("Question: " + question)

	    //create variable i (short for input)
		var i int
		_, err := fmt.Scanln(&i) //request user input in terminal
		
		//check whether user input is correct or not
		if i == answer2 {
			correct = correct + 1
			question_number = question_number + 1
			fmt.Println("CORRECT")
		    } else {
			fmt.Println("INCORRECT", err)
			question_number = question_number + 1
		    }
		}
}
	fmt.Println("you got this many questions correct")
	fmt.Println(correct)
	fmt.Println(question_number)
}

The Python code is, as you would expect, a lot less verbose. We simply define the starting time (which is now), we say that we have a limit of 10 and then with each loop say ‘has the limit been exceeded?’.

If it hasn’t, we read the columns in, ask the user for an answer and verify that the answer is correct.

import csv
import time

starting_time = time.time()
time_limit = 10

with open('quiz.csv') as csv_file:
    csv_reader = csv.reader(csv_file, delimiter=',')
    q_count = 0
    score = 0
    for row in csv_reader:
        if time.time() - starting_time < time_limit:
            question = row[0]
            answer = row[1]

            print('Question' + str(q_count) + ": " + question)
            user_answer = input('What is your answer?')

            if user_answer == answer:
                score = score + 1

            q_count = q_count + 1
    print('your final score was: ' + str(score))
    print('you answered ' + str(q_count) + " questions")
Kodey