Skip to content

Commit

Permalink
Quiz example (gophercises#3)
Browse files Browse the repository at this point in the history
* Implemented the quiz.
Most of the quiz is completed. Randomization was not directly implemented. Instead the map data structure was used with the range operator, which results in random access of the map elements (the ordering of Go maps is not defined for integers?).
I'll try to implement a better random sequence of questions later.

* Implemented random question generation switched by command line flag -random.
This completely implements the quiz according to the specification.
  • Loading branch information
barisere authored and joncalhoun committed Oct 5, 2017
1 parent 6378856 commit 4c5cce0
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
13 changes: 13 additions & 0 deletions students/latentgenius/questions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
5+5,10
7+3,10
8+3,11
8+6,14
1+1,2
1+2,3
3+1,4
1+4,5
2+3,5
5+1,6
3+3,6
2+4,6
5+2,7
141 changes: 141 additions & 0 deletions students/latentgenius/quiz.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package main

import (
"bufio"
"encoding/csv"
"flag"
"fmt"
"io"
"log"
"math/rand"
"os"
"path/filepath"
"strings"
"sync"
"time"
)

var (
flagFilePath string
flagRandom bool
flagTime int
wg sync.WaitGroup
)

func init() {
flag.StringVar(&flagFilePath, "file", "questions.csv", "path/to/csv_file")
flag.BoolVar(&flagRandom, "random", true, "randomize order of questions")
flag.IntVar(&flagTime, "time", 10, "test duration")
flag.Parse()
}

func main() {
// this program will progress as follows
// read a csv filepath and a time limit from flags
// prompt for a key press
// on key press, start the quiz as follows
//
// while time has not elapsed:
// print a random question to the screen
// prompt the user for an answer
// store the answer in a container
// normalize answers so they compare correctly
// output total questions answered correctly and how many questions there
// were.

csvPath, err := filepath.Abs(flagFilePath)
if err != nil {
log.Fatalln("Unable to parse path" + csvPath)
}
file, err := os.Open(csvPath)
if err != nil {
log.Fatalln(err)
}
defer file.Close()

csvReader := csv.NewReader(file)
csvData, err := csvReader.ReadAll()
if err != nil {
log.Fatalln(err)
}

var totalQuestions = len(csvData)
questions := make(map[int]string, totalQuestions)
answers := make(map[int]string, totalQuestions)
responses := make(map[int]string, totalQuestions)

for i, data := range csvData {
questions[i] = data[0]
answers[i] = data[1]
}

respondTo := make(chan string)

// block until user presses enter
fmt.Println("Press [Enter] to start test.")
bufio.NewScanner(os.Stdout).Scan()
if flagRandom {
// seed the random number generator with the current time
rand.Seed(time.Now().UTC().UnixNano())
}
// randPool should contain random indexes into the questions map
randPool := rand.Perm(totalQuestions)

wg.Add(1)
timeUp := time.After(time.Second * time.Duration(flagTime))
go func() {
label:
for i := 0; i < totalQuestions; i++ {
index := randPool[i]
go askQuestion(os.Stdout, os.Stdin, questions[index], respondTo)
select {
case <-timeUp:
fmt.Fprintln(os.Stderr, "\nTime up!")
break label
case ans, ok := <-respondTo:
if ok {
responses[index] = ans
} else {
break label
}
}
}
wg.Done()
}()
wg.Wait()

correct := 0
for i := 0; i < totalQuestions; i++ {
if checkAnswer(answers[i], responses[i]) {
correct++
}
}
summary(correct, totalQuestions)
}

func askQuestion(w io.Writer, r io.Reader, question string, replyTo chan string) {
reader := bufio.NewReader(r)
fmt.Fprintln(w, "Question: "+question)
fmt.Fprint(w, "Answer: ")
answer, err := reader.ReadString('\n')
if err != nil {
close(replyTo)
if err == io.EOF {
return
}
log.Fatalln(err)
}
replyTo <- answer
}

func checkAnswer(ans string, expected string) bool {
if strings.EqualFold(strings.TrimSpace(ans), strings.TrimSpace(expected)) {
return true
}
return false
}

func summary(correct, totalQuestions int) {
fmt.Fprintf(os.Stdout, "You answered %d questions correctly (%d / %d)\n", correct,
correct, totalQuestions)
}

0 comments on commit 4c5cce0

Please sign in to comment.