From 6d9a7b168cf72ab92ec9232a98e57170c4f619c3 Mon Sep 17 00:00:00 2001
From: Jon Calhoun <joncalhoun@gmail.com>
Date: Fri, 13 Oct 2017 12:42:53 -0400
Subject: [PATCH 1/4] Finished p1

---
 main.go      | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 problems.csv | 12 +----------
 2 files changed, 59 insertions(+), 11 deletions(-)
 create mode 100644 main.go

diff --git a/main.go b/main.go
new file mode 100644
index 0000000..1a735a5
--- /dev/null
+++ b/main.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"encoding/csv"
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+)
+
+func main() {
+	csvFilename := flag.String("csv", "problems.csv", "a csv file in the format of 'question,answer'")
+	flag.Parse()
+
+	file, err := os.Open(*csvFilename)
+	if err != nil {
+		exit(fmt.Sprintf("Failed to open the CSV file: %s\n", *csvFilename))
+	}
+	r := csv.NewReader(file)
+	lines, err := r.ReadAll()
+	if err != nil {
+		exit("Failed to parse the provided CSV file.")
+	}
+	problems := parseLines(lines)
+
+	correct := 0
+	for i, p := range problems {
+		fmt.Printf("Problem #%d: %s = \n", i+1, p.q)
+		var answer string
+		fmt.Scanf("%s\n", &answer)
+		if answer == p.a {
+			correct++
+		}
+	}
+
+	fmt.Printf("You scored %d out of %d.\n", correct, len(problems))
+}
+
+func parseLines(lines [][]string) []problem {
+	ret := make([]problem, len(lines))
+	for i, line := range lines {
+		ret[i] = problem{
+			q: line[0],
+			a: strings.TrimSpace(line[1]),
+		}
+	}
+	return ret
+}
+
+type problem struct {
+	q string
+	a string
+}
+
+func exit(msg string) {
+	fmt.Println(msg)
+	os.Exit(1)
+}
diff --git a/problems.csv b/problems.csv
index 11506cb..610d2e0 100644
--- a/problems.csv
+++ b/problems.csv
@@ -1,12 +1,2 @@
-5+5,10
+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

From f78e310604a640f8a16078925cffa8bbe514252d Mon Sep 17 00:00:00 2001
From: Jon Calhoun <joncalhoun@gmail.com>
Date: Fri, 13 Oct 2017 15:24:41 -0400
Subject: [PATCH 2/4] Finished Part 2

---
 main.go      | 26 +++++++++++++++++++++-----
 problems.csv | 12 +++++++++++-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/main.go b/main.go
index 1a735a5..1d58f43 100644
--- a/main.go
+++ b/main.go
@@ -6,10 +6,12 @@ import (
 	"fmt"
 	"os"
 	"strings"
+	"time"
 )
 
 func main() {
 	csvFilename := flag.String("csv", "problems.csv", "a csv file in the format of 'question,answer'")
+	timeLimit := flag.Int("limit", 30, "the time limit for the quiz in seconds")
 	flag.Parse()
 
 	file, err := os.Open(*csvFilename)
@@ -23,13 +25,27 @@ func main() {
 	}
 	problems := parseLines(lines)
 
+	timer := time.NewTimer(time.Duration(*timeLimit) * time.Second)
 	correct := 0
+
+problemloop:
 	for i, p := range problems {
-		fmt.Printf("Problem #%d: %s = \n", i+1, p.q)
-		var answer string
-		fmt.Scanf("%s\n", &answer)
-		if answer == p.a {
-			correct++
+		fmt.Printf("Problem #%d: %s = ", i+1, p.q)
+		answerCh := make(chan string)
+		go func() {
+			var answer string
+			fmt.Scanf("%s\n", &answer)
+			answerCh <- answer
+		}()
+
+		select {
+		case <-timer.C:
+			fmt.Println()
+			break problemloop
+		case answer := <-answerCh:
+			if answer == p.a {
+				correct++
+			}
 		}
 	}
 
diff --git a/problems.csv b/problems.csv
index 610d2e0..11506cb 100644
--- a/problems.csv
+++ b/problems.csv
@@ -1,2 +1,12 @@
-5+5,  10
+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

From c7609c1e50f86f450bd69551dbf8109b07026419 Mon Sep 17 00:00:00 2001
From: Jon Calhoun <joncalhoun@gmail.com>
Date: Fri, 13 Oct 2017 15:25:18 -0400
Subject: [PATCH 3/4] Reverting the problems csv

---
 problems.csv | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/problems.csv b/problems.csv
index 610d2e0..11506cb 100644
--- a/problems.csv
+++ b/problems.csv
@@ -1,2 +1,12 @@
-5+5,  10
+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

From 3b2250f3d56e07dd320f5c6272febe7827988d3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sin=C3=A9sio=20Neto?= <sinetoami@gmail.com>
Date: Mon, 22 Jul 2019 10:13:02 -0300
Subject: [PATCH 4/4] add sinetoami's solution for Part 2 (#44)

---
 students/sinetoami/main.go | 85 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 students/sinetoami/main.go

diff --git a/students/sinetoami/main.go b/students/sinetoami/main.go
new file mode 100644
index 0000000..575abb1
--- /dev/null
+++ b/students/sinetoami/main.go
@@ -0,0 +1,85 @@
+// Package main provides a command that starts a quiz based on a CSV file.
+package main
+
+import (
+	"encoding/csv"
+	"flag"
+	"fmt"
+	"math/rand"
+	"os"
+	"sort"
+	"strings"
+	"time"
+)
+
+// Problem represents a quis' problem structure.
+type Problem struct {
+	question, answer string
+}
+
+// QuizProblems stores each problem from a given CSV file to a variable.
+// If the shuffle flag is true will randomize the problems order.
+func QuizProblems(lines [][]string, shuffle bool) []Problem {
+	problems := make([]Problem, len(lines))
+	rand.Seed(time.Now().UTC().UnixNano())
+
+	// create a list with random items (int)
+	perm := rand.Perm(len(lines))
+
+	if !shuffle {
+		sort.Ints(perm[:])
+	}
+
+	for i, v := range perm {
+		problems[v] = Problem{lines[i][0], lines[i][1]}
+	}
+
+	return problems
+}
+
+func main() {
+	filename := flag.String("csv", "problems.csv", "a csv file in the format of 'question,answer' (default \"problems.csv\")")
+	limit := flag.Int("limit", 30, "the time limit for the quiz in seconds (default 30)")
+	shuffle := flag.Bool("shuffle", false, "shuffle the quiz order each time it is run if pass value 'true' (default false)")
+	flag.Parse()
+
+	file, err := os.Open(*filename)
+	if err != nil {
+		fmt.Errorf("failed to open CSV file: %v", err)
+	}
+	defer file.Close()
+
+	lines, err := csv.NewReader(file).ReadAll()
+	if err != nil {
+		fmt.Errorf("filed to read lines from file: %v", err)
+	}
+
+	score := 0
+	timer := time.NewTimer(time.Duration(*limit) * time.Second)
+	problems := QuizProblems(lines, *shuffle)
+
+quizloop:
+	for i, problem := range problems {
+		fmt.Printf("Problem #%d: %s = \n", i+1, problem.question)
+
+		// if the user don't type the answer before the timer is done
+		// will terminate the quiz.
+		answerChan := make(chan string)
+		go func() {
+			userAnswer := ""
+			fmt.Scanf("%s\n", &userAnswer)
+			answerChan <- strings.TrimSpace(userAnswer)
+		}()
+
+		select {
+		case an := <-answerChan:
+			if an == problem.answer {
+				score++
+			}
+		case <-timer.C:
+			break quizloop
+		}
+	}
+
+	fmt.Printf("You scored %d out of %d.", score, len(problems))
+}