mirror of
https://github.com/AmanTahiliani/gophercises.git
synced 2026-08-07 11:53:44 -04:00
Different solution for Gophercise 1
This commit is contained in:
16
1. Quiz Game Sol2/.gitignore
vendored
Normal file
16
1. Quiz Game Sol2/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||||
|
.glide/
|
||||||
|
|
||||||
|
quiz
|
||||||
56
1. Quiz Game Sol2/README.md
Normal file
56
1. Quiz Game Sol2/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Exercise #1: Quiz Game
|
||||||
|
|
||||||
|
[](https://gophercises.com/exercises/quiz)
|
||||||
|
|
||||||
|
## Exercise details
|
||||||
|
|
||||||
|
This exercise is broken into two parts to help simplify the process of explaining it as well as to make it easier to solve. The second part is harder than the first, so if you get stuck feel free to move on to another problem then come back to part 2 later.
|
||||||
|
|
||||||
|
*Note: I didn't break this into multiple exercises like I do for some exercises because both of these combined should only take ~30m to cover in screencasts.*
|
||||||
|
|
||||||
|
### Part 1
|
||||||
|
|
||||||
|
Create a program that will read in a quiz provided via a CSV file (more details below) and will then give the quiz to a user keeping track of how many questions they get right and how many they get incorrect. Regardless of whether the answer is correct or wrong the next question should be asked immediately afterwards.
|
||||||
|
|
||||||
|
The CSV file should default to `problems.csv` (example shown below), but the user should be able to customize the filename via a flag.
|
||||||
|
|
||||||
|
The CSV file will be in a format like below, where the first column is a question and the second column in the same row is the answer to that question.
|
||||||
|
|
||||||
|
```
|
||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
```
|
||||||
|
|
||||||
|
You can assume that quizzes will be relatively short (< 100 questions) and will have single word/number answers.
|
||||||
|
|
||||||
|
At the end of the quiz the program should output the total number of questions correct and how many questions there were in total. Questions given invalid answers are considered incorrect.
|
||||||
|
|
||||||
|
**NOTE:** *CSV files may have questions with commas in them. Eg: `"what 2+2, sir?",4` is a valid row in a CSV. I suggest you look into the CSV package in Go and don't try to write your own CSV parser.*
|
||||||
|
|
||||||
|
### Part 2
|
||||||
|
|
||||||
|
Adapt your program from part 1 to add a timer. The default time limit should be 30 seconds, but should also be customizable via a flag.
|
||||||
|
|
||||||
|
Your quiz should stop as soon as the time limit has exceeded. That is, you shouldn't wait for the user to answer one final questions but should ideally stop the quiz entirely even if you are currently waiting on an answer from the end user.
|
||||||
|
|
||||||
|
Users should be asked to press enter (or some other key) before the timer starts, and then the questions should be printed out to the screen one at a time until the user provides an answer. Regardless of whether the answer is correct or wrong the next question should be asked.
|
||||||
|
|
||||||
|
At the end of the quiz the program should still output the total number of questions correct and how many questions there were in total. Questions given invalid answers or unanswered are considered incorrect.
|
||||||
|
|
||||||
|
## Bonus
|
||||||
|
|
||||||
|
As a bonus exercises you can also...
|
||||||
|
|
||||||
|
1. Add string trimming and cleanup to help ensure that correct answers with extra whitespace, capitalization, etc are not considered incorrect. *Hint: Check out the [strings](https://golang.org/pkg/strings/) package.*
|
||||||
|
2. Add an option (a new flag) to shuffle the quiz order each time it is run.
|
||||||
98
1. Quiz Game Sol2/main.go
Normal file
98
1. Quiz Game Sol2/main.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Question struct {
|
||||||
|
question string
|
||||||
|
correctAnswer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCSV(filenName string) [][]string {
|
||||||
|
log.Println("Opening CSV file from filepath", filenName)
|
||||||
|
f, err := os.Open(filenName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("%+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
csvReader := csv.NewReader(f)
|
||||||
|
|
||||||
|
records, err := csvReader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("%+v", err)
|
||||||
|
}
|
||||||
|
return records
|
||||||
|
}
|
||||||
|
|
||||||
|
func timer(seconds int, c chan int) {
|
||||||
|
time.Sleep(time.Second * time.Duration(seconds))
|
||||||
|
c <- -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQuestionsFromCSV(fileName string) []Question {
|
||||||
|
records := readCSV(fileName)
|
||||||
|
|
||||||
|
var questions []Question
|
||||||
|
|
||||||
|
for _, record := range records {
|
||||||
|
question := Question{record[0], record[1]}
|
||||||
|
questions = append(questions, question)
|
||||||
|
|
||||||
|
}
|
||||||
|
return questions
|
||||||
|
}
|
||||||
|
|
||||||
|
func strip(s string) string {
|
||||||
|
return strings.ReplaceAll(s, " ", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func askQuestion(question Question, c chan int) {
|
||||||
|
var userAnswer int
|
||||||
|
|
||||||
|
fmt.Printf("%s? :", question.question)
|
||||||
|
fmt.Scan(&userAnswer)
|
||||||
|
fmt.Print("\n")
|
||||||
|
userAnswerString := strconv.Itoa(userAnswer)
|
||||||
|
|
||||||
|
if userAnswerString == question.correctAnswer {
|
||||||
|
fmt.Println("Answer is Correct!")
|
||||||
|
c <- 1
|
||||||
|
} else {
|
||||||
|
fmt.Println("Answer is Incorrect :(")
|
||||||
|
c <- 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
csvFileName := flag.String("fileName", "problems.csv", "file name string")
|
||||||
|
timeLimit := flag.Int("timeLimit", 30, "time in seconds")
|
||||||
|
flag.Parse()
|
||||||
|
questions := getQuestionsFromCSV(*csvFileName)
|
||||||
|
|
||||||
|
score := 0
|
||||||
|
c := make(chan int)
|
||||||
|
go timer(*timeLimit, c)
|
||||||
|
for _, question := range questions {
|
||||||
|
go askQuestion(question, c)
|
||||||
|
event := <-c
|
||||||
|
|
||||||
|
if event == -1 {
|
||||||
|
fmt.Printf("\n\nOops! Time is up!\n Final Score: %d\n", score)
|
||||||
|
os.Exit(0)
|
||||||
|
} else {
|
||||||
|
score += event
|
||||||
|
fmt.Printf("Score: %d\n", score)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/problems.csv
Normal file
12
1. Quiz Game Sol2/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
8
1. Quiz Game Sol2/students/README.md
Normal file
8
1. Quiz Game Sol2/students/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Student Examples
|
||||||
|
|
||||||
|
The following are example implementations submitted by students/gophers learning from this course.
|
||||||
|
|
||||||
|
The primary purposes of these examples are:
|
||||||
|
|
||||||
|
1. To provide example implementations to discuss and review when recording the screencasts for this course.
|
||||||
|
2. To provide a way for students to contribute to this course.
|
||||||
13
1. Quiz Game Sol2/students/abdul/problem.csv
Normal file
13
1. Quiz Game Sol2/students/abdul/problem.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
131
1. Quiz Game Sol2/students/abdul/quiz.go
Normal file
131
1. Quiz Game Sol2/students/abdul/quiz.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package quiz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Number of Questions to ask
|
||||||
|
const totalQuestions = 5
|
||||||
|
|
||||||
|
//Question struct that stores question with answer
|
||||||
|
type Question struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filename, timeLimit := readArguments()
|
||||||
|
f, err := openFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
questions, err := readCSV(f)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// err := fmt.Errorf("Error in Reading Questions")
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if questions == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
score, err := askQuestion(questions, timeLimit)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Your Score %d/%d\n", score, totalQuestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readArguments() (string, int) {
|
||||||
|
filename := flag.String("filename", "problem.csv", "CSV File that conatins quiz questions")
|
||||||
|
timeLimit := flag.Int("limit", 30, "Time Limit for each question")
|
||||||
|
flag.Parse()
|
||||||
|
return *filename, *timeLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCSV(f io.Reader) ([]Question, error) {
|
||||||
|
// defer f.Close() // this needs to be after the err check
|
||||||
|
allQuestions, err := csv.NewReader(f).ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfQues := len(allQuestions)
|
||||||
|
if numOfQues == 0 {
|
||||||
|
return nil, fmt.Errorf("No Question in file")
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []Question
|
||||||
|
for _, line := range allQuestions {
|
||||||
|
ques := Question{}
|
||||||
|
ques.question = line[0]
|
||||||
|
ques.answer = line[1]
|
||||||
|
data = append(data, ques)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func openFile(filename string) (io.Reader, error) {
|
||||||
|
return os.Open(filename)
|
||||||
|
}
|
||||||
|
func getInput(input chan string) {
|
||||||
|
for {
|
||||||
|
in := bufio.NewReader(os.Stdin)
|
||||||
|
result, err := in.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
input <- result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func askQuestion(questions []Question, timeLimit int) (int, error) {
|
||||||
|
totalScore := 0
|
||||||
|
timer := time.NewTimer(time.Duration(timeLimit) * time.Second)
|
||||||
|
done := make(chan string)
|
||||||
|
|
||||||
|
go getInput(done)
|
||||||
|
|
||||||
|
for i := range [totalQuestions]int{} {
|
||||||
|
ans, err := eachQuestion(questions[i].question, questions[i].answer, timer.C, done)
|
||||||
|
if err != nil && ans == -1 {
|
||||||
|
return totalScore, nil
|
||||||
|
}
|
||||||
|
totalScore += ans
|
||||||
|
|
||||||
|
}
|
||||||
|
return totalScore, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func eachQuestion(Quest string, answer string, timer <-chan time.Time, done <-chan string) (int, error) {
|
||||||
|
fmt.Printf("%s: ", Quest)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timer:
|
||||||
|
return -1, fmt.Errorf("Time out")
|
||||||
|
case ans := <-done:
|
||||||
|
score := 0
|
||||||
|
if strings.Compare(strings.Trim(strings.ToLower(ans), "\n"), answer) == 0 {
|
||||||
|
score = 1
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("Wrong Answer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return score, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
1. Quiz Game Sol2/students/abdul/quiz_test.go
Normal file
59
1. Quiz Game Sol2/students/abdul/quiz_test.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package quiz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gotest.tools/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testEachQuestion(t *testing.T) {
|
||||||
|
timer := time.NewTimer(time.Duration(2) * time.Second).C
|
||||||
|
done := make(chan string)
|
||||||
|
var quest Question
|
||||||
|
quest.question = "1+1"
|
||||||
|
quest.answer = "2"
|
||||||
|
var ans int
|
||||||
|
var err error
|
||||||
|
allDone := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
ans, err = eachQuestion(quest.question, quest.answer, timer, done)
|
||||||
|
allDone <- true
|
||||||
|
}()
|
||||||
|
done <- "2"
|
||||||
|
|
||||||
|
<-allDone
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, ans, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReadCSV(t *testing.T) {
|
||||||
|
str := "1+1,2\n2+1,3\n9+9,18\n"
|
||||||
|
quest, err := readCSV(strings.NewReader(str))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
var que [3]Question
|
||||||
|
que[0].answer = "2"
|
||||||
|
que[1].answer = "3"
|
||||||
|
que[2].answer = "18"
|
||||||
|
que[0].question = "1+1"
|
||||||
|
que[1].question = "2+1"
|
||||||
|
que[2].question = "9+9"
|
||||||
|
|
||||||
|
assert.Equal(t, que[0], quest[0])
|
||||||
|
assert.Equal(t, que[1], quest[1])
|
||||||
|
assert.Equal(t, que[2], quest[2])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEachQuestion(t *testing.T) {
|
||||||
|
t.Run("test eachQuestion", testEachQuestion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCSV(t *testing.T) {
|
||||||
|
t.Run("test ReadCSV", testReadCSV)
|
||||||
|
}
|
||||||
137
1. Quiz Game Sol2/students/andreis/main.go
Normal file
137
1. Quiz Game Sol2/students/andreis/main.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/csv"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
const timeToAnswer = 5 * time.Second
|
||||||
|
|
||||||
|
type quiz struct {
|
||||||
|
challenge, response string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *quiz) ask(timeout time.Duration, lines <-chan string, roundOver chan<- struct{}) bool {
|
||||||
|
color.Set(color.FgGreen)
|
||||||
|
fmt.Print("> ")
|
||||||
|
color.Unset()
|
||||||
|
fmt.Println(q.challenge)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case line := <-lines:
|
||||||
|
return clean(line) == clean(q.response)
|
||||||
|
case <-time.After(timeout):
|
||||||
|
color.Set(color.FgRed)
|
||||||
|
fmt.Println("Out of time")
|
||||||
|
color.Unset()
|
||||||
|
|
||||||
|
roundOver <- struct{}{}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
fmt.Println(`USAGE: go run main.go <CSV_FILE>`)
|
||||||
|
fmt.Println(len(os.Args))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
qs, err := readCSV(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to read file %s: %v\n", os.Args[1], err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := make(chan string)
|
||||||
|
roundOver := make(chan struct{})
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeToAnswer*time.Duration(len(qs)))
|
||||||
|
|
||||||
|
go listenForUserInput(ctx, bufio.NewReader(os.Stdin), lines, roundOver)
|
||||||
|
|
||||||
|
good := 0
|
||||||
|
for _, q := range qs {
|
||||||
|
if q.ask(timeToAnswer, lines, roundOver) {
|
||||||
|
good++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
fmt.Printf("Answered %d/%d questions.\n", good, len(qs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func clean(a string) string {
|
||||||
|
return strings.TrimSpace(strings.ToLower(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
func listenForUserInput(ctx context.Context, r io.RuneReader, lines chan<- string, roundOver <-chan struct{}) {
|
||||||
|
inputRunes := []rune{}
|
||||||
|
newline := false
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
close(lines)
|
||||||
|
return
|
||||||
|
case <-roundOver:
|
||||||
|
inputRunes = inputRunes[:0]
|
||||||
|
newline = false
|
||||||
|
default:
|
||||||
|
if newline {
|
||||||
|
lines <- string(inputRunes)
|
||||||
|
inputRunes = inputRunes[:0]
|
||||||
|
newline = false
|
||||||
|
}
|
||||||
|
|
||||||
|
run, _, err := r.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Couldn't read rune:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if run == '\n' {
|
||||||
|
newline = true
|
||||||
|
} else {
|
||||||
|
inputRunes = append(inputRunes, run)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCSV(filename string) ([]quiz, error) {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't open file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close() // nolint
|
||||||
|
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
out := []quiz{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
record, err := r.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while reading CSV record: %v", err)
|
||||||
|
}
|
||||||
|
if len(record) != 2 {
|
||||||
|
return nil, fmt.Errorf("unexpected number of fields for record: %v", record)
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, quiz{record[0], record[1]})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
97
1. Quiz Game Sol2/students/bart/main.go
Normal file
97
1. Quiz Game Sol2/students/bart/main.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fatalError(message string, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(message, ":", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type question struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
type quiz struct {
|
||||||
|
answered int
|
||||||
|
answeredCorrectly int
|
||||||
|
questions []question
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadQuiz loads all questions into memory, assumed to be safe as
|
||||||
|
// the instructions state that the quiz will be < 100 questions
|
||||||
|
func loadQuiz(filePath string) *quiz {
|
||||||
|
csvFile, err := os.Open(filePath)
|
||||||
|
fatalError("Error opening quiz CSV file", err)
|
||||||
|
defer csvFile.Close()
|
||||||
|
reader := csv.NewReader(bufio.NewReader(csvFile))
|
||||||
|
var quiz quiz
|
||||||
|
for {
|
||||||
|
line, err := reader.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fatalError("Error parsing CSV", err)
|
||||||
|
question := question{line[0], line[1]}
|
||||||
|
quiz.questions = append(quiz.questions, question)
|
||||||
|
}
|
||||||
|
return &quiz
|
||||||
|
}
|
||||||
|
|
||||||
|
// run prints questions, check answers, and records total
|
||||||
|
// answered and total correct
|
||||||
|
func (quiz *quiz) run() {
|
||||||
|
timer := time.NewTimer(time.Duration(*timeLimit) * time.Second)
|
||||||
|
quizLoop:
|
||||||
|
for _, question := range quiz.questions {
|
||||||
|
fmt.Println(question.question)
|
||||||
|
answerCh := make(chan string)
|
||||||
|
go func() {
|
||||||
|
scanner.Scan()
|
||||||
|
answer := scanner.Text()
|
||||||
|
answerCh <- answer
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
break quizLoop
|
||||||
|
case answer := <-answerCh:
|
||||||
|
if answer == question.answer {
|
||||||
|
quiz.answeredCorrectly++
|
||||||
|
}
|
||||||
|
quiz.answered++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// report prints summary of quiz performance
|
||||||
|
func (quiz *quiz) report() {
|
||||||
|
fmt.Printf(
|
||||||
|
"You answered %v questions out of a total of %v and got %v correct",
|
||||||
|
quiz.answered,
|
||||||
|
len(quiz.questions),
|
||||||
|
quiz.answeredCorrectly,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
scanner = bufio.NewScanner(os.Stdin)
|
||||||
|
filePathPtr = flag.String("file", "./problems.csv", "Path to csv file containing quiz.")
|
||||||
|
timeLimit = flag.Int64("time-limit", 30, "Set the total time in seconds allowed for the quiz.")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
quiz := loadQuiz(*filePathPtr)
|
||||||
|
quiz.run()
|
||||||
|
quiz.report()
|
||||||
|
}
|
||||||
88
1. Quiz Game Sol2/students/csos95/main.go
Normal file
88
1. Quiz Game Sol2/students/csos95/main.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// set flags
|
||||||
|
csvPath = flag.String("csv", "problems.csv", "a csv file in the format of 'question,answer'")
|
||||||
|
limit = flag.Int("limit", 30, "the time limit for the quiz in seconds'")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// parse the flags
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// open the csv file
|
||||||
|
file, err := os.Open(*csvPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// open the csv file
|
||||||
|
csvReader := csv.NewReader(file)
|
||||||
|
// parse the csv file
|
||||||
|
csvData, err := csvReader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// put question/answer pairs into a map where questions are keys and answers are values
|
||||||
|
qaPair := make(map[string]string, len(csvData))
|
||||||
|
for _, data := range csvData {
|
||||||
|
qaPair[data[0]] = data[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a ticker for the time limit and a channel to signal the user finished the quiz
|
||||||
|
ticker := time.NewTicker(time.Second * time.Duration(*limit))
|
||||||
|
done := make(chan bool)
|
||||||
|
|
||||||
|
// create a scanner for user input
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
|
||||||
|
var userAnswer string
|
||||||
|
qNum, numCorrect := 0, 0
|
||||||
|
go func() {
|
||||||
|
// iteration order for maps in go is randomized so the questions won't be in the same order every time
|
||||||
|
for question, answer := range qaPair {
|
||||||
|
qNum++
|
||||||
|
// ask a question
|
||||||
|
fmt.Printf("Problem #%d: %s = ", qNum, question)
|
||||||
|
// get an answer
|
||||||
|
scanner.Scan()
|
||||||
|
userAnswer = scanner.Text()
|
||||||
|
// trim leading and trailing whitespace
|
||||||
|
userAnswer = strings.TrimSpace(userAnswer)
|
||||||
|
userAnswer = strings.ToLower(userAnswer)
|
||||||
|
answer = strings.ToLower(answer)
|
||||||
|
// check the answer
|
||||||
|
if answer == userAnswer {
|
||||||
|
numCorrect++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
// select chooses the first channel with an available value
|
||||||
|
// if done is available first, the user finished
|
||||||
|
// if ticker is available first, the time limit has been reached
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-ticker.C:
|
||||||
|
fmt.Println("time's up!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the results
|
||||||
|
fmt.Printf("You scored %d out of %d.\n", numCorrect, len(qaPair))
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/csos95/problems.csv
Normal file
12
1. Quiz Game Sol2/students/csos95/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
155
1. Quiz Game Sol2/students/dennisvis/main.go
Normal file
155
1. Quiz Game Sol2/students/dennisvis/main.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type problem struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
problemsFile = flag.String("problems", "problems.csv", "A CSV file containing problems and their solutions")
|
||||||
|
quizTime = flag.Int("time", 30, "The time in seconds this quiz will run")
|
||||||
|
shuffle = flag.Bool("shuffle", false, "Wheteher or not to shuffle the problems")
|
||||||
|
osR = bufio.NewReader(os.Stdin)
|
||||||
|
)
|
||||||
|
|
||||||
|
func readProblems(csvFile *os.File) []problem {
|
||||||
|
csvR := csv.NewReader(csvFile)
|
||||||
|
|
||||||
|
problems := make([]problem, 0)
|
||||||
|
for {
|
||||||
|
record, err := csvR.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if record[0] != "" && record[1] != "" {
|
||||||
|
problems = append(problems, problem{record[0], strings.ToLower(record[1]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return problems
|
||||||
|
}
|
||||||
|
|
||||||
|
func shuffleProblems(problems []problem) {
|
||||||
|
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||||
|
for i1 := 0; i1 < len(problems); i1++ {
|
||||||
|
i2 := r.Intn(len(problems))
|
||||||
|
|
||||||
|
problem1 := problems[i1]
|
||||||
|
problem2 := problems[i2]
|
||||||
|
|
||||||
|
problems[i1] = problem2
|
||||||
|
problems[i2] = problem1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func askQuestion(q string, tries int8) string {
|
||||||
|
fmt.Printf("\n%s: ", q)
|
||||||
|
input, err := osR.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
if tries < 5 {
|
||||||
|
log.Println("Your answer could not be processed, please try again")
|
||||||
|
return askQuestion(q, tries+1)
|
||||||
|
}
|
||||||
|
log.Fatal("Something is wrong with this program, going to exit...")
|
||||||
|
}
|
||||||
|
return strings.ToLower(strings.TrimSpace(strings.TrimRight(input, "\n")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func askQuestions(problems []problem, timer, correctAnswersChan, done chan interface{}) {
|
||||||
|
index := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timer:
|
||||||
|
fmt.Println("\nTime's up!")
|
||||||
|
return
|
||||||
|
|
||||||
|
default:
|
||||||
|
if index >= len(problems) {
|
||||||
|
close(done)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
problem := problems[index]
|
||||||
|
answer := askQuestion(problem.question, 0)
|
||||||
|
if answer == problem.answer {
|
||||||
|
correctAnswersChan <- true
|
||||||
|
fmt.Println("Correct!")
|
||||||
|
} else {
|
||||||
|
fmt.Println("False...")
|
||||||
|
}
|
||||||
|
index = index + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if !strings.HasSuffix(*problemsFile, "csv") {
|
||||||
|
log.Fatalf("Provided problems file '%s' is not a CSV file", *problemsFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
csvFile, err := os.Open(*problemsFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not open '%s'", *problemsFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
problems := readProblems(csvFile)
|
||||||
|
totalProblems := len(problems)
|
||||||
|
if *shuffle {
|
||||||
|
shuffleProblems(problems)
|
||||||
|
}
|
||||||
|
|
||||||
|
timer := make(chan interface{})
|
||||||
|
correctAnswersChan := make(chan interface{})
|
||||||
|
done := make(chan interface{})
|
||||||
|
|
||||||
|
fmt.Println("Press ENTER to start the quiz...")
|
||||||
|
osR.ReadString('\n')
|
||||||
|
|
||||||
|
correctAnswers := 0
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-correctAnswersChan:
|
||||||
|
correctAnswers = correctAnswers + 1
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go askQuestions(problems, timer, correctAnswersChan, done)
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(*quizTime) * time.Second)
|
||||||
|
close(timer)
|
||||||
|
close(done)
|
||||||
|
|
||||||
|
if totalProblems == correctAnswers {
|
||||||
|
fmt.Println("\nCongratulations! You answered all questions correctly!")
|
||||||
|
} else {
|
||||||
|
fmt.Printf(
|
||||||
|
"\nYou answered %d questions correctly but failed to do so for %d questions, try again",
|
||||||
|
correctAnswers,
|
||||||
|
totalProblems-correctAnswers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/dennisvis/problems.csv
Normal file
12
1. Quiz Game Sol2/students/dennisvis/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
13
1. Quiz Game Sol2/students/dimdiden/problems.csv
Normal file
13
1. Quiz Game Sol2/students/dimdiden/problems.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
87
1. Quiz Game Sol2/students/dimdiden/quiz.go
Normal file
87
1. Quiz Game Sol2/students/dimdiden/quiz.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DEFAULTFILE is the quiz file expected to be load by default
|
||||||
|
const DEFAULTFILE = "problems.csv"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Flag block
|
||||||
|
file := flag.String("f", DEFAULTFILE, "specify the path to file")
|
||||||
|
timeout := flag.Int("t", 0, "specify the number of seconds for timeout")
|
||||||
|
flag.Parse()
|
||||||
|
// Failed if the number of seconds is negative
|
||||||
|
if *timeout < 0 {
|
||||||
|
flag.PrintDefaults()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
// Open file
|
||||||
|
f, err := os.Open(*file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
// Run the main logic
|
||||||
|
total, correct, err := run(f, *timeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Number of questions: %v\nNumber of correct answers: %v\n", total, correct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run is the main function to execute quiz app
|
||||||
|
func run(qinput io.Reader, timeout int) (total, correct int, err error) {
|
||||||
|
// Reading csv file and parse it to the records var
|
||||||
|
r := csv.NewReader(qinput)
|
||||||
|
records, err := r.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return total, correct, err
|
||||||
|
}
|
||||||
|
// Two channels. One for answers, another for timeout
|
||||||
|
answerChan := make(chan string)
|
||||||
|
timerChan := make(chan time.Time, 1)
|
||||||
|
// Iterate over the records
|
||||||
|
for _, record := range records {
|
||||||
|
question, expected := record[0], record[1]
|
||||||
|
fmt.Printf("Question: %v. Answer: ", question)
|
||||||
|
total++
|
||||||
|
// Listening for input in the separate goroutine
|
||||||
|
go getAnswer(answerChan)
|
||||||
|
// Run the timer in separate goroutine if the timeout is specified
|
||||||
|
if timeout > 0 {
|
||||||
|
go func() { timerChan <- <-time.After(time.Duration(timeout) * time.Second) }()
|
||||||
|
}
|
||||||
|
// Main select block
|
||||||
|
select {
|
||||||
|
case answer := <-answerChan:
|
||||||
|
if answer == expected {
|
||||||
|
correct++
|
||||||
|
}
|
||||||
|
case <-timerChan:
|
||||||
|
fmt.Println()
|
||||||
|
return total, correct, errors.New("Timeout reached!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total, correct, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAnswer func is for listening input from user
|
||||||
|
func getAnswer(answerChan chan string) {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
answer, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
answerChan <- strings.Replace(answer, "\n", "", -1)
|
||||||
|
}
|
||||||
85
1. Quiz Game Sol2/students/ehernandez/main.go
Normal file
85
1. Quiz Game Sol2/students/ehernandez/main.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type quiz struct {
|
||||||
|
total int
|
||||||
|
correct int
|
||||||
|
incorrect int
|
||||||
|
items []*item
|
||||||
|
}
|
||||||
|
type item struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
got string
|
||||||
|
correct bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file := flag.String("file", "problems.csv", "file to parse the quiz")
|
||||||
|
flag.Parse()
|
||||||
|
qz, err := load(*file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start(qz)
|
||||||
|
score(qz)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// load loads the values of the file and return a new quiz
|
||||||
|
func load(file string) (*quiz, error) {
|
||||||
|
f, err := os.OpenFile(file, os.O_RDONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
all, err := r.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
qz := new(quiz)
|
||||||
|
qz.total = len(all)
|
||||||
|
|
||||||
|
for _, items := range all {
|
||||||
|
i := item{question: items[0], answer: items[1]}
|
||||||
|
qz.items = append(qz.items, &i)
|
||||||
|
}
|
||||||
|
return qz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// score prints the quiz score
|
||||||
|
func score(qz *quiz) {
|
||||||
|
fmt.Printf("total: %v correct: %v incorrect: %v\n", qz.total, qz.correct, qz.incorrect)
|
||||||
|
fmt.Println("Incorrect questions")
|
||||||
|
for _, q := range qz.items {
|
||||||
|
if !q.correct {
|
||||||
|
fmt.Printf("%v answer: %v got: %v\n", q.question, q.answer, q.got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start starts the quiz
|
||||||
|
func start(qz *quiz) {
|
||||||
|
fmt.Printf("interactive mode (%v questions in quiz)\n", qz.total)
|
||||||
|
for i, item := range qz.items {
|
||||||
|
var op = ""
|
||||||
|
fmt.Printf("%v) %v?: ", i+1, item.question)
|
||||||
|
fmt.Scanln(&op)
|
||||||
|
item.got = op
|
||||||
|
if op == item.answer {
|
||||||
|
qz.correct++
|
||||||
|
item.correct = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
qz.incorrect++
|
||||||
|
}
|
||||||
|
}
|
||||||
4
1. Quiz Game Sol2/students/ehernandez/p2.csv
Normal file
4
1. Quiz Game Sol2/students/ehernandez/p2.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
2x2,4
|
||||||
|
5x6,30
|
||||||
|
8x2,16
|
||||||
|
9x6,54
|
||||||
|
13
1. Quiz Game Sol2/students/ehernandez/problems.csv
Normal file
13
1. Quiz Game Sol2/students/ehernandez/problems.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
13
1. Quiz Game Sol2/students/emrekp/problems.csv
Normal file
13
1. Quiz Game Sol2/students/emrekp/problems.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
"Surname of 9th President of Turkey","Demirel"
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
"First name of first woman PM of UK","Margaret"
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
60
1. Quiz Game Sol2/students/emrekp/quiz.go
Normal file
60
1. Quiz Game Sol2/students/emrekp/quiz.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startTime(timer time.Timer, duration time.Duration) {
|
||||||
|
<-timer.C
|
||||||
|
fmt.Println(duration, "doldu")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filename := flag.String("file", "problems.csv", "Questions file")
|
||||||
|
timelimit := flag.Int("time", 30, "Time limit of quiz in seconds")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
filePath, pathErr := filepath.Abs(*filename)
|
||||||
|
if pathErr != nil {
|
||||||
|
log.Fatal("file not found. check if it exists again.")
|
||||||
|
}
|
||||||
|
|
||||||
|
remainTime := time.Duration(*timelimit) * time.Second
|
||||||
|
fmt.Println("Press return to start time (", remainTime, ")")
|
||||||
|
fmt.Scanln() //and time starts
|
||||||
|
|
||||||
|
timer := time.NewTimer(remainTime)
|
||||||
|
go startTime(*timer, remainTime)
|
||||||
|
|
||||||
|
csvF, csvErr := ioutil.ReadFile(filePath)
|
||||||
|
if csvErr != nil {
|
||||||
|
log.Fatal("error reading file: " + csvErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
probs, probErr := csv.NewReader(strings.NewReader(string(csvF))).ReadAll()
|
||||||
|
if probErr != nil {
|
||||||
|
log.Fatal("error on CSV format: " + probErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var answer string
|
||||||
|
var trues, total int
|
||||||
|
|
||||||
|
for i, soru := range probs {
|
||||||
|
fmt.Printf("%d. soru: %s = ", i+1, soru[0])
|
||||||
|
fmt.Scan(&answer)
|
||||||
|
if answer == soru[1] {
|
||||||
|
trues++
|
||||||
|
}
|
||||||
|
total++
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("True answers: %d\n", trues)
|
||||||
|
fmt.Printf("Total questions: %d\n", total)
|
||||||
|
}
|
||||||
BIN
1. Quiz Game Sol2/students/hackeryarn/hackeryarn
Executable file
BIN
1. Quiz Game Sol2/students/hackeryarn/hackeryarn
Executable file
Binary file not shown.
120
1. Quiz Game Sol2/students/hackeryarn/main.go
Normal file
120
1. Quiz Game Sol2/students/hackeryarn/main.go
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
quiz "github.com/gophercises/quiz/students/hackeryarn/myquiz"
|
||||||
|
"github.com/gophercises/quiz/students/hackeryarn/problem"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FileFlag is used to set a file for the questions
|
||||||
|
FileFlag = "file"
|
||||||
|
// FileFlagValue is the value used when no FileFlag is provided
|
||||||
|
FileFlagValue = "problems.csv"
|
||||||
|
// FileFlagUsage is the help string for the FileFlag
|
||||||
|
FileFlagUsage = "Questions file"
|
||||||
|
|
||||||
|
// TimerFlag is used for setting a timer for the quiz
|
||||||
|
TimerFlag = "timer"
|
||||||
|
// TimerFlagValue is the value used when no TimerFlag is provided
|
||||||
|
TimerFlagValue = 30
|
||||||
|
// TimerFlagUsage is the help string for the TimerFlag
|
||||||
|
TimerFlagUsage = "Amount of seconds the quiz will allow"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flagger configures the flags used
|
||||||
|
type Flagger interface {
|
||||||
|
StringVar(p *string, name, value, usage string)
|
||||||
|
IntVar(p *int, name string, value int, usage string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type quizFlagger struct{}
|
||||||
|
|
||||||
|
func (q *quizFlagger) StringVar(p *string, name, value, usage string) {
|
||||||
|
flag.StringVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *quizFlagger) IntVar(p *int, name string, value int, usage string) {
|
||||||
|
flag.IntVar(p, name, value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer is used to start a timer
|
||||||
|
type Timer interface {
|
||||||
|
NewTimer(d time.Duration) *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
type quizTimer struct{}
|
||||||
|
|
||||||
|
func (q quizTimer) NewTimer(d time.Duration) *time.Timer {
|
||||||
|
return time.NewTimer(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadCSV parses the CSV file into a Problem struct
|
||||||
|
func ReadCSV(reader io.Reader) quiz.Quiz {
|
||||||
|
csvReader := csv.NewReader(reader)
|
||||||
|
|
||||||
|
problems := []problem.Problem{}
|
||||||
|
for {
|
||||||
|
record, err := csvReader.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
log.Fatalln("Error reading CSV:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
problems = append(problems, problem.New(record))
|
||||||
|
}
|
||||||
|
|
||||||
|
return quiz.New(problems)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimerSeconds is the amount of time allowed for the quiz
|
||||||
|
var TimerSeconds int
|
||||||
|
var file string
|
||||||
|
|
||||||
|
// ConfigFlags sets all the flags used by the application
|
||||||
|
func ConfigFlags(f Flagger) {
|
||||||
|
f.StringVar(&file, FileFlag, FileFlagValue, FileFlagUsage)
|
||||||
|
f.IntVar(&TimerSeconds, TimerFlag, TimerFlagValue, TimerFlagUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTimer begins a timer once the user provides input
|
||||||
|
func StartTimer(w io.Writer, r io.Reader, timer Timer) *time.Timer {
|
||||||
|
fmt.Fprint(w, "Ready to start?")
|
||||||
|
fmt.Fscanln(r)
|
||||||
|
|
||||||
|
return timer.NewTimer(time.Second * time.Duration(TimerSeconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flagger := &quizFlagger{}
|
||||||
|
ConfigFlags(flagger)
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Could not open file", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
quiz := ReadCSV(file)
|
||||||
|
|
||||||
|
timer := StartTimer(os.Stdout, os.Stdin, quizTimer{})
|
||||||
|
go func() {
|
||||||
|
<-timer.C
|
||||||
|
fmt.Println("")
|
||||||
|
quiz.PrintResults(os.Stdout)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
|
||||||
|
quiz.Run(os.Stdout, os.Stdin)
|
||||||
|
}
|
||||||
40
1. Quiz Game Sol2/students/hackeryarn/myquiz/myquiz.go
Normal file
40
1. Quiz Game Sol2/students/hackeryarn/myquiz/myquiz.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package quiz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/gophercises/quiz/students/hackeryarn/problem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Quiz represents the quiz to be given to the user
|
||||||
|
type Quiz struct {
|
||||||
|
problems []problem.Problem
|
||||||
|
rightAnswers int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the quiz for all the problems keeping track of correct answers
|
||||||
|
func (q *Quiz) Run(w io.Writer, r io.Reader) {
|
||||||
|
for _, problem := range q.problems {
|
||||||
|
problem.AskQuestion(w)
|
||||||
|
correct := problem.CheckAnswer(r)
|
||||||
|
if correct {
|
||||||
|
q.rightAnswers++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q.PrintResults(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintResults outputs the results of the quiz
|
||||||
|
func (q Quiz) PrintResults(w io.Writer) {
|
||||||
|
fmt.Fprintf(w, "You got %d questions right!\n", q.rightAnswers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new quiz from the supplied slice of problems
|
||||||
|
func New(problems []problem.Problem) Quiz {
|
||||||
|
return Quiz{
|
||||||
|
problems: problems,
|
||||||
|
rightAnswers: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
66
1. Quiz Game Sol2/students/hackeryarn/myquiz/myquiz_test.go
Normal file
66
1. Quiz Game Sol2/students/hackeryarn/myquiz/myquiz_test.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package quiz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gophercises/quiz/students/hackeryarn/problem"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
problems := sampleProblems()
|
||||||
|
|
||||||
|
want := Quiz{problems: problems, rightAnswers: 0}
|
||||||
|
got := New(problems)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(want, got) {
|
||||||
|
t.Errorf("expeted to create quiz %v got %v", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRun(t *testing.T) {
|
||||||
|
t.Run("it runs the quiz", func(t *testing.T) {
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
quiz := createQuiz()
|
||||||
|
runQuiz(buffer, &quiz)
|
||||||
|
|
||||||
|
expectedResults := 2
|
||||||
|
results := quiz.rightAnswers
|
||||||
|
|
||||||
|
if expectedResults != results {
|
||||||
|
t.Errorf("expected right answers of %v, got %v",
|
||||||
|
expectedResults, results)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := "7+3: 1+1: You got 2 questions right!\n"
|
||||||
|
|
||||||
|
if buffer.String() != expectedOutput {
|
||||||
|
t.Errorf("expected full output %v, got %v",
|
||||||
|
expectedOutput, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func sampleProblems() []problem.Problem {
|
||||||
|
record1 := []string{"7+3", "10"}
|
||||||
|
record2 := []string{"1+1", "2"}
|
||||||
|
|
||||||
|
return []problem.Problem{
|
||||||
|
problem.New(record1),
|
||||||
|
problem.New(record2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createQuiz() Quiz {
|
||||||
|
problems := sampleProblems()
|
||||||
|
return New(problems)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runQuiz(buffer io.Writer, quiz *Quiz) {
|
||||||
|
answers := strings.NewReader("10\n2\n")
|
||||||
|
quiz.Run(buffer, answers)
|
||||||
|
}
|
||||||
49
1. Quiz Game Sol2/students/hackeryarn/problem/problem.go
Normal file
49
1. Quiz Game Sol2/students/hackeryarn/problem/problem.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package problem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Problem represents a single question answer pair
|
||||||
|
type Problem struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckAnswer checks the answer against the provided input
|
||||||
|
func (p Problem) CheckAnswer(r io.Reader) bool {
|
||||||
|
answer := readAnswer(r)
|
||||||
|
|
||||||
|
if answer != p.answer {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAnswer(r io.Reader) (answer string) {
|
||||||
|
_, err := fmt.Fscanln(r, &answer)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error reading in answer", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(answer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AskQuestion prints out the question
|
||||||
|
func (p Problem) AskQuestion(w io.Writer) {
|
||||||
|
_, err := fmt.Fprintf(w, "%s: ", p.question)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Could not ask the question", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a Problem from a provided CSV record
|
||||||
|
func New(record []string) Problem {
|
||||||
|
return Problem{
|
||||||
|
question: record[0],
|
||||||
|
answer: record[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package problem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
record := []string{"question", "answer"}
|
||||||
|
|
||||||
|
want := Problem{"question", "answer"}
|
||||||
|
got := New(record)
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("expected to create problem %v got %v", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckAnswer(t *testing.T) {
|
||||||
|
problem := createProblem()
|
||||||
|
|
||||||
|
t.Run("it checks the correct answer", func(t *testing.T) {
|
||||||
|
answer := getAnswer(problem, "10\n")
|
||||||
|
|
||||||
|
checkAnswer(t, answer, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("it checks incorrect answer", func(t *testing.T) {
|
||||||
|
answer := getAnswer(problem, "2\n")
|
||||||
|
|
||||||
|
checkAnswer(t, answer, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAskQuestion(t *testing.T) {
|
||||||
|
problem := createProblem()
|
||||||
|
|
||||||
|
t.Run("it asks the question", func(t *testing.T) {
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
problem.AskQuestion(buffer)
|
||||||
|
|
||||||
|
want := "7+3: "
|
||||||
|
got := buffer.String()
|
||||||
|
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Expected question %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func createProblem() Problem {
|
||||||
|
record := []string{"7+3", "10"}
|
||||||
|
return New(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAnswer(problem Problem, input string) bool {
|
||||||
|
r := bytes.NewBufferString(input)
|
||||||
|
|
||||||
|
return problem.CheckAnswer(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAnswer(t *testing.T, got, want bool) {
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Expected to return %v got %v", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/hackeryarn/problems.csv
Normal file
12
1. Quiz Game Sol2/students/hackeryarn/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
136
1. Quiz Game Sol2/students/hackeryarn/quiz_test.go
Normal file
136
1. Quiz Game Sol2/students/hackeryarn/quiz_test.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
quiz "github.com/gophercises/quiz/students/hackeryarn/myquiz"
|
||||||
|
"github.com/gophercises/quiz/students/hackeryarn/problem"
|
||||||
|
)
|
||||||
|
|
||||||
|
type flaggerMock struct {
|
||||||
|
stringVarCalls int
|
||||||
|
intVarCalls int
|
||||||
|
varNames []string
|
||||||
|
varUsages []string
|
||||||
|
varStringValues []string
|
||||||
|
varIntValues []int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flaggerMock) StringVar(p *string, name, value, usage string) {
|
||||||
|
f.stringVarCalls++
|
||||||
|
f.varNames = append(f.varNames, name)
|
||||||
|
f.varStringValues = append(f.varStringValues, value)
|
||||||
|
f.varUsages = append(f.varUsages, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flaggerMock) IntVar(p *int, name string, value int, usage string) {
|
||||||
|
f.intVarCalls++
|
||||||
|
f.varNames = append(f.varNames, name)
|
||||||
|
f.varIntValues = append(f.varIntValues, value)
|
||||||
|
f.varUsages = append(f.varUsages, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
type timerMock struct {
|
||||||
|
duration int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *timerMock) NewTimer(d time.Duration) *time.Timer {
|
||||||
|
t.duration = int(d.Seconds())
|
||||||
|
return time.NewTimer(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCSV(t *testing.T) {
|
||||||
|
input := "7+3,10\n1+1,2"
|
||||||
|
reader := bytes.NewBufferString(input)
|
||||||
|
|
||||||
|
record1 := []string{"7+3", "10"}
|
||||||
|
record2 := []string{"1+1", "2"}
|
||||||
|
problems := []problem.Problem{
|
||||||
|
problem.New(record1),
|
||||||
|
problem.New(record2),
|
||||||
|
}
|
||||||
|
|
||||||
|
want := quiz.New(problems)
|
||||||
|
got := ReadCSV(reader)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(want, got) {
|
||||||
|
t.Errorf("it should read in %v got %v", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigFlags(t *testing.T) {
|
||||||
|
flagger := &flaggerMock{}
|
||||||
|
|
||||||
|
ConfigFlags(flagger)
|
||||||
|
|
||||||
|
assertStringCalls(t, flagger)
|
||||||
|
assertIntCalls(t, flagger)
|
||||||
|
assertFlags(t, flagger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStartTimer(t *testing.T) {
|
||||||
|
timer := &timerMock{}
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
r := bytes.NewBufferString("\n")
|
||||||
|
TimerSeconds := 30
|
||||||
|
|
||||||
|
StartTimer(w, r, timer)
|
||||||
|
|
||||||
|
if timer.duration != TimerSeconds {
|
||||||
|
t.Errorf("it should set timer for %d seconds, set for %d",
|
||||||
|
TimerSeconds, timer.duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.String() != "Ready to start?" {
|
||||||
|
t.Errorf("it should ask user if the user is ready, got %s", w.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertStringCalls(t *testing.T, flagger *flaggerMock) {
|
||||||
|
t.Helper()
|
||||||
|
if flagger.stringVarCalls != 1 {
|
||||||
|
t.Errorf("it should call StringVar %d times, called %d",
|
||||||
|
1, flagger.stringVarCalls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertIntCalls(t *testing.T, flagger *flaggerMock) {
|
||||||
|
t.Helper()
|
||||||
|
if flagger.intVarCalls != 1 {
|
||||||
|
t.Errorf("it should call IntVar %d times, called %d",
|
||||||
|
1, flagger.intVarCalls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertFlags(t *testing.T, flagger *flaggerMock) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
expectedNames := []string{FileFlag, TimerFlag}
|
||||||
|
expectedUsages := []string{FileFlagUsage, TimerFlagUsage}
|
||||||
|
expectedStringValues := []string{FileFlagValue}
|
||||||
|
expectedIntValues := []int{TimerFlagValue}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedNames, flagger.varNames) {
|
||||||
|
t.Errorf("it should setup flag names to be %v, got %v",
|
||||||
|
expectedNames, flagger.varNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedUsages, flagger.varUsages) {
|
||||||
|
t.Errorf("it should setup flag usages to be %v, got %v",
|
||||||
|
expectedUsages, flagger.varUsages)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedStringValues, flagger.varStringValues) {
|
||||||
|
t.Errorf("it should setup string values to be %v, got %v",
|
||||||
|
expectedStringValues, flagger.varStringValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedIntValues, flagger.varIntValues) {
|
||||||
|
t.Errorf("it should setup int values to be %v, got %v",
|
||||||
|
expectedIntValues, flagger.varIntValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
81
1. Quiz Game Sol2/students/hellosputnik/main.go
Normal file
81
1. Quiz Game Sol2/students/hellosputnik/main.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Problem struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Quiz struct {
|
||||||
|
problems []Problem
|
||||||
|
score int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
filename *string
|
||||||
|
timeLimit *int
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
quiz := Quiz{}
|
||||||
|
settings := Settings{}
|
||||||
|
|
||||||
|
settings.filename = flag.String("csv", "problems.csv", "a csv file in the format of 'question,answer'")
|
||||||
|
settings.timeLimit = flag.Int("limit", 30, "the time limit for the quiz in seconds")
|
||||||
|
|
||||||
|
// Get the flags (if any).
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Create a file handle for the file.
|
||||||
|
file, err := os.Open(*settings.filename)
|
||||||
|
|
||||||
|
// If there was an error opening the file, exit.
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Create a buffered reader to read the file input.
|
||||||
|
fin := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
// Read the problems from the comma-separated values file.
|
||||||
|
for fin.Scan() {
|
||||||
|
line := strings.Split(fin.Text(), ",")
|
||||||
|
problem := Problem{question: line[0], answer: line[1]}
|
||||||
|
|
||||||
|
quiz.problems = append(quiz.problems, problem)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a timer to enforce a time limit.
|
||||||
|
timer := time.NewTimer(time.Second * time.Duration(*settings.timeLimit))
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-timer.C
|
||||||
|
fmt.Printf("\nYou scored %d out of %d.", quiz.score, len(quiz.problems))
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Quiz the user.
|
||||||
|
for i, problem := range quiz.problems {
|
||||||
|
fmt.Printf("Problem #%d: %s = ", (i + 1), problem.question)
|
||||||
|
|
||||||
|
var input string
|
||||||
|
fmt.Scan(&input)
|
||||||
|
|
||||||
|
if input == problem.answer {
|
||||||
|
quiz.score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the user's results.
|
||||||
|
fmt.Printf("You scored %d out of %d.", quiz.score, len(quiz.problems))
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/inyutin/problems.csv
Normal file
12
1. Quiz Game Sol2/students/inyutin/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
73
1. Quiz Game Sol2/students/inyutin/quiz.go
Normal file
73
1. Quiz Game Sol2/students/inyutin/quiz.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Line struct {
|
||||||
|
Question string
|
||||||
|
Answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
csvName = flag.String("csv", "problems.csv", "path to csv file with quiz(question,answer)")
|
||||||
|
limit = flag.Int("limit", 30, "the time limit for the quiz in seconds")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
csvFile, err := os.Open(*csvName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer csvFile.Close()
|
||||||
|
|
||||||
|
csvReader := csv.NewReader(bufio.NewReader(csvFile))
|
||||||
|
var lines []Line
|
||||||
|
for {
|
||||||
|
line, error := csvReader.Read()
|
||||||
|
if error == io.EOF {
|
||||||
|
break
|
||||||
|
} else if error != nil {
|
||||||
|
log.Fatal(error)
|
||||||
|
}
|
||||||
|
lines = append(lines, Line{
|
||||||
|
Question: line[0],
|
||||||
|
Answer: line[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
T := time.Duration(*limit)
|
||||||
|
timer := time.NewTimer(T * time.Second)
|
||||||
|
go func() {
|
||||||
|
<-timer.C
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("You scored " + strconv.Itoa(count) + " out of " + strconv.Itoa(len(lines)))
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for idx, line := range lines {
|
||||||
|
fmt.Print("Question №" + strconv.Itoa(idx+1) + ": " + line.Question + " = ")
|
||||||
|
ans, _ := reader.ReadString('\n')
|
||||||
|
if ans == line.Answer+"\n" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop := timer.Stop()
|
||||||
|
if stop {
|
||||||
|
fmt.Println("You scored " + strconv.Itoa(count) + " out of " + strconv.Itoa(len(lines)))
|
||||||
|
}
|
||||||
|
}
|
||||||
112
1. Quiz Game Sol2/students/kalexmills/main.go
Normal file
112
1. Quiz Game Sol2/students/kalexmills/main.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
filename string
|
||||||
|
timelimit time.Duration
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&filename, "in", "problems.csv", "filename where problems are read from")
|
||||||
|
flag.DurationVar(&timelimit, "time", 30*time.Second, "time to allot for quiz")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// problem represents a prompt and the correct response
|
||||||
|
type problem struct {
|
||||||
|
prompt string
|
||||||
|
response string
|
||||||
|
}
|
||||||
|
|
||||||
|
// printResults prints a prompt to the user explaining the results achieved.
|
||||||
|
func printResults(nWrong, nTotal int) {
|
||||||
|
nRight := nTotal - nWrong
|
||||||
|
fmt.Printf("You answered %d out of %d questions correctly.\n", nRight, nTotal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readFile reads from the file, sending back a slice of problems.
|
||||||
|
func readFile() []problem {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error opening file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
r := csv.NewReader(file)
|
||||||
|
records, err := r.ReadAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct a slice of problems for later consumption
|
||||||
|
result := make([]problem, len(records))
|
||||||
|
var i int
|
||||||
|
for idx, rec := range records {
|
||||||
|
if len(rec) < 2 {
|
||||||
|
fmt.Println("Ignoring faulty or missing record from line %d", idx)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result[i] = problem{rec[0], rec[1]}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
problems := readFile()
|
||||||
|
|
||||||
|
var nWrong, nDone int
|
||||||
|
// timeout is used to signal that the timer has elapsed
|
||||||
|
timeout := make(chan bool, 2)
|
||||||
|
timer := time.AfterFunc(timelimit, func() {
|
||||||
|
timeout <- true // signal that a timeout occurred
|
||||||
|
})
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
// Ask each question and get a response
|
||||||
|
for _, prob := range problems {
|
||||||
|
fmt.Printf("%s\n > ", prob.prompt)
|
||||||
|
|
||||||
|
// A separate goroutine must be used to accept input from each question. At first I tried to just read from
|
||||||
|
// Stdin on the main thread. That was a mistake. If you want to be able to interrupt the prompt when the time
|
||||||
|
// expires, you need to have your main thread waiting on a response from either the timer or the answer thread.
|
||||||
|
//
|
||||||
|
// Lesson is to treat user input as an asynchronous message!
|
||||||
|
answerCh := make(chan string)
|
||||||
|
go func() {
|
||||||
|
var answer string
|
||||||
|
fmt.Scanf("%s\n", &answer)
|
||||||
|
answerCh <- answer
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
fmt.Println("\nTimes up!")
|
||||||
|
nWrong += len(problems) - nDone // All remaining problems are marked wrong
|
||||||
|
printResults(nWrong, len(problems))
|
||||||
|
os.Exit(0)
|
||||||
|
case response := <-answerCh:
|
||||||
|
nDone++
|
||||||
|
if prob.response != response {
|
||||||
|
nWrong++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if timer.Stop() {
|
||||||
|
fmt.Printf("You completed the quiz with %s remaining\n", (timelimit - time.Since(startTime)).String())
|
||||||
|
|
||||||
|
printResults(nWrong, len(problems))
|
||||||
|
}
|
||||||
|
}
|
||||||
13
1. Quiz Game Sol2/students/kalexmills/problems.csv
Normal file
13
1. Quiz Game Sol2/students/kalexmills/problems.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
57
1. Quiz Game Sol2/students/kannanenator/main.go
Normal file
57
1. Quiz Game Sol2/students/kannanenator/main.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
import "fmt"
|
||||||
|
import "log"
|
||||||
|
import "flag"
|
||||||
|
import "time"
|
||||||
|
import "encoding/csv"
|
||||||
|
import "bufio"
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
filenamePtr := flag.String("filename", "problems.csv", "file containing the set of problems")
|
||||||
|
limitPtr := flag.Int("limit", 30, "quiz time limit")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
file, err := os.Open(*filenamePtr)
|
||||||
|
handleError(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
csvReader := csv.NewReader(file)
|
||||||
|
rows, err := csvReader.ReadAll()
|
||||||
|
handleError(err)
|
||||||
|
|
||||||
|
numQs := len(rows)
|
||||||
|
numCorrect := 0
|
||||||
|
|
||||||
|
timer := time.NewTimer(time.Second * time.Duration(*limitPtr))
|
||||||
|
go func() {
|
||||||
|
<- timer.C
|
||||||
|
// when the timer ends, we kill the quiz
|
||||||
|
fmt.Println("\nTime is up")
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
|
||||||
|
consoleReader := bufio.NewReader(os.Stdin)
|
||||||
|
for idx, element := range rows {
|
||||||
|
q, a := element[0], element[1]
|
||||||
|
fmt.Print("Problem #", idx+1 ,": ", q, " = ")
|
||||||
|
input, _ := consoleReader.ReadString('\n')
|
||||||
|
|
||||||
|
// compare w/o whitespace
|
||||||
|
if strings.TrimSpace(input) == strings.TrimSpace(a) {
|
||||||
|
numCorrect++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("You got", numCorrect, "out of", numQs, "correct")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleError(err error){
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
99
1. Quiz Game Sol2/students/kdlug/main.go
Normal file
99
1. Quiz Game Sol2/students/kdlug/main.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
csvFile := flag.String("csv", "problems.csv", "csv file with questions and answers")
|
||||||
|
duration := flag.Int("time", 30, "quiz time limit")
|
||||||
|
randomize := flag.Bool("random", false, "randomize questions")
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
questions := loadRecordsFromCsv(*csvFile)
|
||||||
|
correct := 0
|
||||||
|
total := len(questions) - 1
|
||||||
|
|
||||||
|
if *randomize {
|
||||||
|
questions = shuffle(questions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Total Questions:", total)
|
||||||
|
fmt.Println("Duration [s]:", *duration)
|
||||||
|
|
||||||
|
done := make(chan bool, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < total; i++ {
|
||||||
|
fmt.Printf("Question #%d %s = ", i+1, questions[i][0])
|
||||||
|
|
||||||
|
answer, _ := reader.ReadString('\n')
|
||||||
|
// convert CRLF to LF
|
||||||
|
answer = strings.Replace(answer, "\n", "", -1)
|
||||||
|
answer = strings.ToLower(answer)
|
||||||
|
answer = strings.TrimSpace(answer)
|
||||||
|
|
||||||
|
// compare answer
|
||||||
|
if strings.Compare(questions[i][1], answer) == 0 {
|
||||||
|
correct++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
fmt.Println("Good Job!")
|
||||||
|
|
||||||
|
case <-time.After(time.Duration(*duration) * time.Second):
|
||||||
|
fmt.Println("\nYou reached maximum time.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Your score:", correct, "/", total)
|
||||||
|
}
|
||||||
|
|
||||||
|
// shuffle questions
|
||||||
|
func shuffle(questions [][]string) [][]string {
|
||||||
|
s := rand.NewSource(time.Now().UnixNano())
|
||||||
|
r := rand.New(s)
|
||||||
|
|
||||||
|
for i := range questions {
|
||||||
|
np := r.Intn(len(questions) - 1)
|
||||||
|
questions[i], questions[np] = questions[np], questions[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return questions
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadRecordsFromCsv(csvFile string) [][]string {
|
||||||
|
|
||||||
|
// load csv file into memory, returns bytes
|
||||||
|
content, err := ioutil.ReadFile(csvFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := csv.NewReader(bytes.NewReader(content)) // if we have string instead of btes we can use strings.NewReader(content)
|
||||||
|
|
||||||
|
records, err := r.ReadAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records[1:len(records)]
|
||||||
|
}
|
||||||
14
1. Quiz Game Sol2/students/kdlug/problems.csv
Normal file
14
1. Quiz Game Sol2/students/kdlug/problems.csv
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
question,answer
|
||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
13
1. Quiz Game Sol2/students/latentgenius/questions.csv
Normal file
13
1. Quiz Game Sol2/students/latentgenius/questions.csv
Normal file
@@ -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
1. Quiz Game Sol2/students/latentgenius/quiz.go
Normal file
141
1. Quiz Game Sol2/students/latentgenius/quiz.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
77
1. Quiz Game Sol2/students/liikt/main.go
Normal file
77
1. Quiz Game Sol2/students/liikt/main.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
problemsFile string
|
||||||
|
timeout int
|
||||||
|
correct int
|
||||||
|
b bool
|
||||||
|
inChan chan int
|
||||||
|
outChan chan int
|
||||||
|
)
|
||||||
|
|
||||||
|
func getAnswer(solution string) {
|
||||||
|
var inp string
|
||||||
|
fmt.Scanln(&inp)
|
||||||
|
if sanitize(inp) == sanitize(solution) {
|
||||||
|
outChan <- <-inChan + 1
|
||||||
|
} else {
|
||||||
|
outChan <- <-inChan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateCorrect() bool {
|
||||||
|
select {
|
||||||
|
case res := <-outChan:
|
||||||
|
correct = res
|
||||||
|
return true
|
||||||
|
case <-time.After(time.Duration(timeout) * time.Second):
|
||||||
|
close(outChan)
|
||||||
|
fmt.Println()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitize(s string) string {
|
||||||
|
return strings.ToLower(strings.Trim(s, "\n\r\t "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.StringVar(&problemsFile, "path", "problems.csv", "This is the flag to the CSV containing the problems for the quiz")
|
||||||
|
flag.IntVar(&timeout, "timeout", 30, "The amount of time you have for a single question in seconds")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
file, err := os.Open(problemsFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
problems, err := csv.NewReader(file).ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
inChan, outChan = make(chan int, 1), make(chan int, 1)
|
||||||
|
for c, q := range problems {
|
||||||
|
fmt.Printf("Question %v: %v -> ", c, q[0])
|
||||||
|
|
||||||
|
go getAnswer(q[1])
|
||||||
|
inChan <- correct
|
||||||
|
|
||||||
|
if !updateCorrect() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fmt.Println("You got", correct, "out of", len(problems), "correct.")
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/liikt/problems.csv
Normal file
12
1. Quiz Game Sol2/students/liikt/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
118
1. Quiz Game Sol2/students/mastertinner/main.go
Normal file
118
1. Quiz Game Sol2/students/mastertinner/main.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// problem is a problem to be solved by a user.
|
||||||
|
type problem struct {
|
||||||
|
challenge string
|
||||||
|
correctAnswer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// scoreboard keeps track of a user's score.
|
||||||
|
type scoreboard struct {
|
||||||
|
total int64
|
||||||
|
correct int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
csvFileName = flag.String("csv", "problems.csv", "the location of the CSV file")
|
||||||
|
timeLimit = flag.Int("time-limit", 30, "the time limit for the user to answer all problems")
|
||||||
|
doShuffle = flag.Bool("shuffle", false, "whether to shuffle the order of problems or not")
|
||||||
|
)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
problems, err := readProblemsFromCSVFile(*csvFileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Errorf("error reading problems from CSV file: %s", err))
|
||||||
|
}
|
||||||
|
if *doShuffle {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
rand.Shuffle(len(problems), func(i, j int) { problems[i], problems[j] = problems[j], problems[i] })
|
||||||
|
}
|
||||||
|
|
||||||
|
doneCh := make(chan bool)
|
||||||
|
scr := &scoreboard{
|
||||||
|
total: int64(len(problems)),
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i, p := range problems {
|
||||||
|
fmt.Printf("What is %s?\n", p.challenge)
|
||||||
|
inputReader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Print("Answer: ")
|
||||||
|
answer, err := inputReader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Errorf("error reading user input: %s", err))
|
||||||
|
}
|
||||||
|
if purifyString(answer) == purifyString(p.correctAnswer) {
|
||||||
|
scr.correct++
|
||||||
|
fmt.Println("You are correct!")
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Unfortunately not... The correct answer is %s\n", p.correctAnswer)
|
||||||
|
}
|
||||||
|
fmt.Printf("Your current score is %v/%v\n\n", scr.correct, scr.total)
|
||||||
|
if i == len(problems)-1 {
|
||||||
|
doneCh <- true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
timer := time.NewTimer(time.Duration(*timeLimit) * time.Second)
|
||||||
|
<-timer.C
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Println("Your time is up...")
|
||||||
|
doneCh <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-doneCh
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Printf("Your final score is %v/%v\n\n", scr.correct, scr.total)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readProblemsFromCSVFile reads problems from a CSV file.
|
||||||
|
func readProblemsFromCSVFile(fileName string) ([]problem, error) {
|
||||||
|
csvFile, err := os.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error opening file: %s", err)
|
||||||
|
}
|
||||||
|
reader := csv.NewReader(bufio.NewReader(csvFile))
|
||||||
|
var problems []problem
|
||||||
|
for {
|
||||||
|
line, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("error reading CSV line: %s", err)
|
||||||
|
}
|
||||||
|
if len(line) != 2 {
|
||||||
|
return nil, errors.New("invalid line in CSV")
|
||||||
|
}
|
||||||
|
p := problem{
|
||||||
|
challenge: line[0],
|
||||||
|
correctAnswer: line[1],
|
||||||
|
}
|
||||||
|
problems = append(problems, p)
|
||||||
|
}
|
||||||
|
return problems, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// purifyString strips all unneeded variations from a string.
|
||||||
|
func purifyString(str string) string {
|
||||||
|
return strings.TrimSpace(strings.ToLower(str))
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/mielofon/problems.csv
Normal file
12
1. Quiz Game Sol2/students/mielofon/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
90
1. Quiz Game Sol2/students/mielofon/quiz.go
Normal file
90
1. Quiz Game Sol2/students/mielofon/quiz.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type recordtype struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadStringWithLimitTime - function read string from reader with time limit
|
||||||
|
func ReadStringWithLimitTime(limit int) (string, error) {
|
||||||
|
timer := time.NewTimer(time.Duration(limit) * time.Second).C
|
||||||
|
doneChan := make(chan bool)
|
||||||
|
answer, err := "", error(nil)
|
||||||
|
go func() {
|
||||||
|
fmt.Scanf("%s\n", &answer)
|
||||||
|
doneChan <- true
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timer:
|
||||||
|
return "", errors.New("Timer expired")
|
||||||
|
case <-doneChan:
|
||||||
|
return answer, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLines - parse lines from array of array of string to array of recordtype
|
||||||
|
func ParseLines(lines [][]string) []recordtype {
|
||||||
|
ret := make([]recordtype, len(lines))
|
||||||
|
for i, line := range lines {
|
||||||
|
ret[i] = recordtype{
|
||||||
|
question: line[0],
|
||||||
|
answer: strings.TrimSpace(line[1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func exit(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
problemFileName := flag.String("csv", "./problems.csv", "a csv file in the format 'quastion,answer'")
|
||||||
|
limit := flag.Int("limit", 30, "the time limit for the quiz in seconds")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
problemFile, err := os.Open(*problemFileName)
|
||||||
|
if err != nil {
|
||||||
|
exit(fmt.Sprintf("Failed to open the CSV file: %s\n", *problemFileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer problemFile.Close() // close CSV file
|
||||||
|
|
||||||
|
readerProblem := csv.NewReader(problemFile)
|
||||||
|
lines, err := readerProblem.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
exit("Failed to parse the provided CSV file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
problems := ParseLines(lines)
|
||||||
|
|
||||||
|
successAnswerCount := 0
|
||||||
|
for i, p := range problems {
|
||||||
|
fmt.Printf("Problem #%d: %s=", i+1, p.question)
|
||||||
|
|
||||||
|
answer, err := ReadStringWithLimitTime(*limit)
|
||||||
|
if err != nil {
|
||||||
|
println("Time expire!")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if strings.ToLower(strings.Trim(answer, "\n ")) == p.answer {
|
||||||
|
successAnswerCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("You scored", successAnswerCount, "out of", len(problems))
|
||||||
|
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/mirekwalczak/problems.csv
Normal file
12
1. Quiz Game Sol2/students/mirekwalczak/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5, 10
|
||||||
|
"1+1",2
|
||||||
|
8+3, 11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
96
1. Quiz Game Sol2/students/mirekwalczak/quiz.go
Normal file
96
1. Quiz Game Sol2/students/mirekwalczak/quiz.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Quiz is structure for questions and answers
|
||||||
|
type Quiz struct {
|
||||||
|
question, answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat is struct for quiz statistics
|
||||||
|
type Stat struct {
|
||||||
|
all, correct, incorrect int
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCSV(file string) ([]Quiz, error) {
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
var quizes []Quiz
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
for {
|
||||||
|
line, err := r.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
quizes = append(quizes, Quiz{
|
||||||
|
strings.TrimSpace(line[0]),
|
||||||
|
strings.TrimSpace(line[1]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return quizes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func quiz(records []Quiz, timeout int) (*Stat, error) {
|
||||||
|
var stat Stat
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
timer := time.NewTimer(time.Second * time.Duration(timeout))
|
||||||
|
errs := make(chan error)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, quiz := range records {
|
||||||
|
fmt.Print(quiz.question, ":")
|
||||||
|
|
||||||
|
ans, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
errs <- err
|
||||||
|
}
|
||||||
|
stat.all++
|
||||||
|
if strings.TrimRight(ans, "\r\n") == quiz.answer {
|
||||||
|
stat.correct++
|
||||||
|
} else {
|
||||||
|
stat.incorrect++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-errs:
|
||||||
|
return nil, <-errs
|
||||||
|
case <-timer.C:
|
||||||
|
fmt.Println("\ntime's up!")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f := flag.String("f", "problems.csv", "input file in csv format")
|
||||||
|
t := flag.Int("t", 30, "timeout for the quiz, in seconds")
|
||||||
|
flag.Parse()
|
||||||
|
recs, err := readCSV(*f)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
stat, err := quiz(recs, *t)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("\nQuestion answered: %v, Correct: %v, Incorrect: %v\n", stat.all, stat.correct, stat.incorrect)
|
||||||
|
}
|
||||||
159
1. Quiz Game Sol2/students/sewelol/main.go
Normal file
159
1. Quiz Game Sol2/students/sewelol/main.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Problem structure
|
||||||
|
type Problem struct {
|
||||||
|
q string
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEMBUFCOUNT sets number of problems in buffer
|
||||||
|
const PROBLEMBUFCOUNT = 100
|
||||||
|
|
||||||
|
// DEFAULTTIMELIMIT sets the default time limit for the quiz
|
||||||
|
const DEFAULTTIMELIMIT = 30 //seconds
|
||||||
|
|
||||||
|
// Problem counter
|
||||||
|
var count int
|
||||||
|
|
||||||
|
// Score counter
|
||||||
|
var score int
|
||||||
|
var faults int
|
||||||
|
|
||||||
|
// readProblems takes reads problems from file, line by line
|
||||||
|
// problems are written to problems channel
|
||||||
|
func readProblems(problems chan Problem, filename string, shuffle bool) {
|
||||||
|
// problems buffer
|
||||||
|
buf := make([]Problem, PROBLEMBUFCOUNT)
|
||||||
|
|
||||||
|
// Open problems file
|
||||||
|
fd, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
// Scan file
|
||||||
|
scanner := bufio.NewScanner(fd)
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Read comma separated line
|
||||||
|
line := strings.Split(scanner.Text(), ",")
|
||||||
|
// first value is the question string
|
||||||
|
q := line[0]
|
||||||
|
// Convert string answer to integer
|
||||||
|
ans, err := strconv.Atoi(line[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store problem in buffer
|
||||||
|
buf[count] = Problem{q, ans}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
// shuffle problems
|
||||||
|
if shuffle {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
for i := range buf[:count] {
|
||||||
|
j := rand.Intn(i + 1)
|
||||||
|
buf[i], buf[j] = buf[j], buf[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send problems over channel
|
||||||
|
for _, p := range buf[:count] {
|
||||||
|
problems <- p
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// solveProblem consumes problems from chan
|
||||||
|
// will check timer before giving points
|
||||||
|
func solveProblem(problems chan Problem) {
|
||||||
|
// IO reader
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
|
||||||
|
// start consuming problems from channel
|
||||||
|
for p := range problems {
|
||||||
|
|
||||||
|
// Print problem question
|
||||||
|
fmt.Printf("%s = ", p.q)
|
||||||
|
|
||||||
|
// Scan IO
|
||||||
|
scanner.Scan()
|
||||||
|
input := strings.Trim(scanner.Text(), " ") // remove whitespace
|
||||||
|
// convert string answer to integer
|
||||||
|
givenAns, err := strconv.Atoi(input)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("'%s' is not a valid answer\n", input)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check answer and give points
|
||||||
|
if givenAns == p.a {
|
||||||
|
score++
|
||||||
|
fmt.Println("Correct!")
|
||||||
|
} else {
|
||||||
|
faults++
|
||||||
|
fmt.Println("Wrong!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// startTimer blocks for n seconds
|
||||||
|
func startTimer(seconds int) {
|
||||||
|
time.Sleep(time.Duration(seconds) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Parse Command line flags
|
||||||
|
filenamePtr := flag.String("f", "problems.csv", "name of problem csv file")
|
||||||
|
secondsPtr := flag.Int("t", DEFAULTTIMELIMIT, "number of seconds to solve problems")
|
||||||
|
shufflePtr := flag.Bool("s", false, "shuffle questions")
|
||||||
|
debugPtr := flag.Bool("debug", false, "show debug information")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Show debug/logging information
|
||||||
|
if !*debugPtr {
|
||||||
|
log.SetOutput(ioutil.Discard)
|
||||||
|
}
|
||||||
|
log.Println("debug:", *debugPtr)
|
||||||
|
log.Println("filename:", *filenamePtr)
|
||||||
|
log.Println("shuffle:", *shufflePtr)
|
||||||
|
log.Println("timer:", *secondsPtr)
|
||||||
|
|
||||||
|
// Problems channel (buffered)
|
||||||
|
problems := make(chan Problem, PROBLEMBUFCOUNT)
|
||||||
|
|
||||||
|
// read problems goroutine
|
||||||
|
go readProblems(problems, *filenamePtr, *shufflePtr)
|
||||||
|
|
||||||
|
// Prompt to start the game
|
||||||
|
fmt.Printf("Press any key to start the quiz!")
|
||||||
|
bufio.NewScanner(os.Stdin).Scan()
|
||||||
|
|
||||||
|
// solve problems goroutine
|
||||||
|
go solveProblem(problems)
|
||||||
|
|
||||||
|
// start timer barrier
|
||||||
|
startTimer(*secondsPtr)
|
||||||
|
|
||||||
|
// Show final tally
|
||||||
|
fmt.Printf("\nNumber of questions: %d\n", count)
|
||||||
|
fmt.Printf("Correct answers: %d\n", score)
|
||||||
|
fmt.Printf("Incorrect answers: %d\n", faults)
|
||||||
|
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/sewelol/problems.csv
Normal file
12
1. Quiz Game Sol2/students/sewelol/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
108
1. Quiz Game Sol2/students/siredmar/main.go
Normal file
108
1. Quiz Game Sol2/students/siredmar/main.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
file = flag.String("csv", "problems.csv", "a csv file in the format 'question,answer'")
|
||||||
|
limit = flag.Int("limit", 30, "the time limit for the quiz in seconds")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *limit < 0 {
|
||||||
|
fmt.Println("Error: enter positive time limit")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
records, err := read(*file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error: ", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Press enter to start. Time limit is", *limit, "seconds")
|
||||||
|
in := bufio.NewReader(os.Stdin)
|
||||||
|
in.ReadString('\n')
|
||||||
|
|
||||||
|
input := make(chan string)
|
||||||
|
|
||||||
|
quizdone := make(chan bool)
|
||||||
|
timeout := time.NewTicker(time.Duration(*limit) * time.Second)
|
||||||
|
|
||||||
|
go getInput(input)
|
||||||
|
|
||||||
|
var score int
|
||||||
|
var maxscore int
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
maxscore = len(records)
|
||||||
|
for i, v := range records {
|
||||||
|
fmt.Print("Problem #", i+1, ": ", v[0], " = ")
|
||||||
|
text := <-input
|
||||||
|
if text == v[1] {
|
||||||
|
score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
quizdone <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-quizdone:
|
||||||
|
case <-timeout.C:
|
||||||
|
fmt.Println("\nThe time is up! Game over!")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("You scored", score, "out of", maxscore)
|
||||||
|
}
|
||||||
|
|
||||||
|
func read(filename string) ([][]string, error) {
|
||||||
|
dat, err := ioutil.ReadFile(filename)
|
||||||
|
r := csv.NewReader(strings.NewReader(string(dat)))
|
||||||
|
if err == nil {
|
||||||
|
var records [][]string
|
||||||
|
for {
|
||||||
|
record, err := r.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
records = append(records, record)
|
||||||
|
}
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func trim(s string) string {
|
||||||
|
t := strings.Trim(s, "\n")
|
||||||
|
t = strings.Trim(t, " ")
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInput(input chan<- string) {
|
||||||
|
for {
|
||||||
|
in := bufio.NewReader(os.Stdin)
|
||||||
|
result, err := in.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = trim(result)
|
||||||
|
input <- result
|
||||||
|
}
|
||||||
|
}
|
||||||
14
1. Quiz Game Sol2/students/siredmar/problems.csv
Normal file
14
1. Quiz Game Sol2/students/siredmar/problems.csv
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
"What is the favourite food?",pizza
|
||||||
|
5+5,10
|
||||||
|
7+3,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
118
1. Quiz Game Sol2/students/teimurjan/main.go
Normal file
118
1. Quiz Game Sol2/students/teimurjan/main.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Problem object
|
||||||
|
type Problem struct {
|
||||||
|
Question string
|
||||||
|
Answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAnswer validates answer for the problem
|
||||||
|
func (p *Problem) ValidateAnswer(answer string) bool {
|
||||||
|
return p.Answer == answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quiz object
|
||||||
|
type Quiz struct {
|
||||||
|
Problems []Problem
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var file string
|
||||||
|
flag.StringVar(&file, "file", "problems.csv", "--file=path/to/problems/file")
|
||||||
|
var quizTime int
|
||||||
|
flag.IntVar(&quizTime, "time", 30, "--time=15")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
WaitForStart()
|
||||||
|
quiz := Quiz{
|
||||||
|
Problems: ParseProblemsFrom(file),
|
||||||
|
Score: 0,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-time.After(time.Duration(quizTime) * time.Second)
|
||||||
|
ShowTimeIsUpMessage()
|
||||||
|
ShowFinalMessage(quiz.Score, len(quiz.Problems))
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
RunQuiz(&quiz)
|
||||||
|
ShowFinalMessage(quiz.Score, len(quiz.Problems))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForStart makes the program wait for a user to press Enter button
|
||||||
|
func WaitForStart() {
|
||||||
|
fmt.Print("Press 'Enter' to start the quiz.")
|
||||||
|
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseProblemsFrom parses problems from file by the provided path
|
||||||
|
func ParseProblemsFrom(pathToFile string) []Problem {
|
||||||
|
file, err := os.Open(pathToFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("File does not exists")
|
||||||
|
}
|
||||||
|
reader := csv.NewReader(bufio.NewReader(file))
|
||||||
|
var problems []Problem
|
||||||
|
for {
|
||||||
|
line, error := reader.Read()
|
||||||
|
if error == io.EOF {
|
||||||
|
break
|
||||||
|
} else if error != nil {
|
||||||
|
log.Fatal(error)
|
||||||
|
}
|
||||||
|
problems = append(problems, Problem{
|
||||||
|
Question: line[0],
|
||||||
|
Answer: line[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return problems
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunQuiz starts the quiz
|
||||||
|
func RunQuiz(q *Quiz) {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for _, problem := range q.Problems {
|
||||||
|
AskQuestion(&problem)
|
||||||
|
answer := ReadLine(reader)
|
||||||
|
if problem.ValidateAnswer(answer) {
|
||||||
|
q.Score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AskQuestion asks a problem's question
|
||||||
|
func AskQuestion(p *Problem) {
|
||||||
|
fmt.Print(p.Question + " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadLine read a line using buifo.Reader
|
||||||
|
func ReadLine(reader *bufio.Reader) string {
|
||||||
|
str, _, err := reader.ReadLine()
|
||||||
|
if err == io.EOF {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimRight(string(str), "\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowTimeIsUpMessage shows time is up message
|
||||||
|
func ShowTimeIsUpMessage() {
|
||||||
|
fmt.Println("\rTime is up!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowFinalMessage shows final message with the correctness statistics
|
||||||
|
func ShowFinalMessage(correctAnswersCount int, problemsCount int) {
|
||||||
|
fmt.Printf("\rThere is/are %d correct answers given for %d problems.\n", correctAnswersCount, problemsCount)
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/teimurjan/problems.csv
Normal file
12
1. Quiz Game Sol2/students/teimurjan/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
71
1. Quiz Game Sol2/students/vancelongwill/main.go
Normal file
71
1. Quiz Game Sol2/students/vancelongwill/main.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
csvFilename := flag.String("f", "problems.csv", "csv file with 2 columns, question & answer")
|
||||||
|
timeLimit := flag.Int("t", 30, "the time limit for the quiz in seconds")
|
||||||
|
hasShuffle := flag.Bool("s", false, "randomize question order")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
correctCount := 0
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
fmt.Println("Press enter to start the quiz")
|
||||||
|
reader.ReadBytes('\n')
|
||||||
|
|
||||||
|
b, fileErr := os.Open(*csvFilename)
|
||||||
|
if fileErr != nil {
|
||||||
|
fmt.Print(fileErr, "\nFailed to read the CSV file provided")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := csv.NewReader(b)
|
||||||
|
records, csvErr := r.ReadAll()
|
||||||
|
|
||||||
|
if csvErr != nil {
|
||||||
|
fmt.Print(csvErr, "\nFailed to parse the CSV file provided")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.NewTimer(time.Duration(*timeLimit) * time.Second)
|
||||||
|
|
||||||
|
ansCh := make(chan string)
|
||||||
|
getUserInput := func() {
|
||||||
|
userAns, _ := reader.ReadString('\n')
|
||||||
|
ansCh <- strings.TrimSpace(strings.ToLower(userAns))
|
||||||
|
}
|
||||||
|
|
||||||
|
if *hasShuffle {
|
||||||
|
rand.Shuffle(len(records), func(i, j int) {
|
||||||
|
records[i], records[j] = records[j], records[i]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
qLoop:
|
||||||
|
for i, record := range records {
|
||||||
|
fmt.Printf("Question %d:\t%s\t", i+1, record[0])
|
||||||
|
go getUserInput()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timeout.C:
|
||||||
|
fmt.Println("\nToo slow!")
|
||||||
|
break qLoop
|
||||||
|
case ans := <-ansCh:
|
||||||
|
if ans == record[1] {
|
||||||
|
correctCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("You scored %d out of %d!\n", correctCount, len(records))
|
||||||
|
}
|
||||||
12
1. Quiz Game Sol2/students/viveksyngh/problems.csv
Normal file
12
1. Quiz Game Sol2/students/viveksyngh/problems.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
5+5,10
|
||||||
|
1+1,2
|
||||||
|
8+3,11
|
||||||
|
1+2,3
|
||||||
|
8+6,14
|
||||||
|
3+1,4
|
||||||
|
1+4,5
|
||||||
|
5+1,6
|
||||||
|
2+3,5
|
||||||
|
3+3,6
|
||||||
|
2+4,6
|
||||||
|
5+2,7
|
||||||
|
94
1. Quiz Game Sol2/students/viveksyngh/quiz.go
Executable file
94
1. Quiz Game Sol2/students/viveksyngh/quiz.go
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"log"
|
||||||
|
"flag"
|
||||||
|
"time"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Question struct {
|
||||||
|
question string
|
||||||
|
answer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQuestions(filePath string) ([]Question) {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if(err != nil){
|
||||||
|
log.Fatal("Failed to open file.")
|
||||||
|
}
|
||||||
|
reader := csv.NewReader(file)
|
||||||
|
questionList, err := reader.ReadAll()
|
||||||
|
if(err != nil) {
|
||||||
|
log.Fatal("Failed to parse CSV file.")
|
||||||
|
}
|
||||||
|
questions := make([]Question, 0)
|
||||||
|
|
||||||
|
for _, question := range questionList {
|
||||||
|
questions = append(questions, Question{strings.TrimSpace(question[0]),
|
||||||
|
strings.TrimSpace(question[1])})
|
||||||
|
}
|
||||||
|
return questions
|
||||||
|
}
|
||||||
|
|
||||||
|
func Quiz(questions []Question, timer *time.Timer) (score int){
|
||||||
|
|
||||||
|
for i, question := range questions {
|
||||||
|
fmt.Printf("Problem #%d %s : ", i + 1, question.question)
|
||||||
|
answerChannel := make(chan string)
|
||||||
|
go func() {
|
||||||
|
var userAnswer string
|
||||||
|
fmt.Scanln(&userAnswer)
|
||||||
|
answerChannel <- userAnswer
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
fmt.Println("\nTimeout")
|
||||||
|
return score
|
||||||
|
case userAnswer := <- answerChannel:
|
||||||
|
if(strings.TrimSpace(userAnswer) == question.answer) {
|
||||||
|
score += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomize(questions []Question) []Question{
|
||||||
|
n := len(questions)
|
||||||
|
for i := n-1; i>0; i-- {
|
||||||
|
j := rand.Intn(i)
|
||||||
|
temp := questions[i]
|
||||||
|
questions[i] = questions[j]
|
||||||
|
questions[j] = temp
|
||||||
|
}
|
||||||
|
return questions
|
||||||
|
}
|
||||||
|
|
||||||
|
var csvPath string
|
||||||
|
var timeout int
|
||||||
|
var shuffle bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&csvPath, "csv", "problems.csv", "a CSV file in format of 'question,answer'")
|
||||||
|
flag.IntVar(&timeout, "limit", 30, "The time limit of the quiz in seconds")
|
||||||
|
flag.BoolVar(&shuffle, "shuffle", false, "Shuffle the questions (default 'false')")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
fmt.Print("Hit Enter to start the timer:")
|
||||||
|
questions := getQuestions(csvPath)
|
||||||
|
if(shuffle) {
|
||||||
|
questions = randomize(questions)
|
||||||
|
}
|
||||||
|
fmt.Scanln()
|
||||||
|
timer := time.NewTimer(time.Second * time.Duration(timeout))
|
||||||
|
score := Quiz(questions, timer)
|
||||||
|
fmt.Printf("Your scored %d out of %d\n", score, len(questions))
|
||||||
|
}
|
||||||
82
1. Quiz Game Sol2/students/wbgalvao/main.go
Normal file
82
1. Quiz Game Sol2/students/wbgalvao/main.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type question struct {
|
||||||
|
problem string
|
||||||
|
result string
|
||||||
|
}
|
||||||
|
|
||||||
|
type quiz struct {
|
||||||
|
questions []question
|
||||||
|
score int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *quiz) ask() {
|
||||||
|
q.score = 0
|
||||||
|
for _, question := range q.questions {
|
||||||
|
fmt.Println(question.problem)
|
||||||
|
var answer string
|
||||||
|
fmt.Scanln(&answer)
|
||||||
|
if answer == question.result {
|
||||||
|
q.score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCSV(p string) []question {
|
||||||
|
qfile, err := os.Open(p)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not open file: %v\n", err)
|
||||||
|
}
|
||||||
|
defer qfile.Close()
|
||||||
|
csvrd := csv.NewReader(qfile)
|
||||||
|
records, err := csvrd.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not parse .csv: %v\n", err)
|
||||||
|
}
|
||||||
|
var questions []question
|
||||||
|
for _, record := range records {
|
||||||
|
q := question{problem: record[0], result: record[1]}
|
||||||
|
questions = append(questions, q)
|
||||||
|
}
|
||||||
|
return questions
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
qCSV string
|
||||||
|
timeout int
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&qCSV, "quiz", "", "A .csv file with questions and answers.")
|
||||||
|
flag.IntVar(&timeout, "timeout", 30, "The time limit for answering questions.")
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if qCSV == "" {
|
||||||
|
log.Fatalln("a .csv file must be provided through the -quiz flag")
|
||||||
|
}
|
||||||
|
questions := readCSV(qCSV)
|
||||||
|
qz := quiz{questions: questions, score: 0}
|
||||||
|
timeoutCh := time.After(time.Duration(timeout) * time.Second)
|
||||||
|
resultCh := make(chan quiz)
|
||||||
|
go func() {
|
||||||
|
qz.ask()
|
||||||
|
resultCh <- qz
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-resultCh:
|
||||||
|
case <-timeoutCh:
|
||||||
|
fmt.Println("Timeout!")
|
||||||
|
}
|
||||||
|
fmt.Println("Score: ", qz.score)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user