mirror of
https://github.com/AmanTahiliani/gophercises.git
synced 2026-08-07 19:56:17 -04:00
Different solution for Gophercise 1
This commit is contained in:
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