mirror of
https://github.com/AmanTahiliani/gophercises.git
synced 2026-08-08 04:06:16 -04:00
Different solution for Gophercise 1
This commit is contained in:
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user