forked from gophercises/quiz
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add mastertinner's solution (gophercises#46)
- Loading branch information
1 parent
da36ae0
commit c18e401
Showing
1 changed file
with
118 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) | ||
} |