mirror of
https://github.com/AmanTahiliani/gophercises.git
synced 2026-08-08 12:07:19 -04:00
119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
|
|
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))
|
||
|
|
}
|