Skip to content

Commit 216dbd5

Browse files
committed
feat: add obinna quiz implementation
1 parent 82fe91a commit 216dbd5

File tree

6 files changed

+432
-0
lines changed

6 files changed

+432
-0
lines changed

students/obinna/go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module gophersizeEx1
2+
3+
go 1.24.3
4+
5+
require github.com/google/go-cmp v0.7.0 // indirect

students/obinna/main.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"encoding/csv"
7+
"flag"
8+
"fmt"
9+
"io"
10+
"log"
11+
"os"
12+
"path/filepath"
13+
"strings"
14+
"time"
15+
)
16+
17+
func main() {
18+
var file string // flag -f for file
19+
flag.StringVar(&file, "f", "problems.csv", "file location of quiz")
20+
21+
var timeLimit int
22+
flag.IntVar(&timeLimit, "t", 30, "time limit for the quiz")
23+
24+
//parse the flag
25+
flag.Parse()
26+
27+
// validate correct file is used
28+
if err := validatePath(file); err != nil {
29+
log.Fatal(err)
30+
os.Exit(1)
31+
}
32+
33+
problems := NewProblemSheet()
34+
err := problems.populateSheet(file)
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
39+
problems.StartQuiz(time.Duration(timeLimit)*time.Second, os.Stdin, os.Stdout)
40+
problems.DisplayResults(os.Stdout)
41+
}
42+
43+
func validatePath(path string) error {
44+
// validate extension is correct
45+
if filepath.Ext(path) != ".csv" {
46+
return fmt.Errorf("malformed file path: %s contains no csv extension", path)
47+
}
48+
49+
//check that file exists
50+
_, err := os.Stat(path)
51+
if os.IsNotExist(err) {
52+
return fmt.Errorf("path does not exist: %w", err)
53+
} else if err != nil {
54+
return fmt.Errorf("error getting file info: %w", err)
55+
}
56+
57+
return nil
58+
}
59+
60+
type Problem struct {
61+
Question string
62+
Answer string
63+
}
64+
65+
type ProblemSheet struct {
66+
Questions []Problem
67+
CorrectlyAnswered int
68+
}
69+
70+
func (p *ProblemSheet) populateSheet(file string) error {
71+
//open file
72+
f, err := os.Open(file)
73+
if err != nil {
74+
return fmt.Errorf("failed to open file: %w", err)
75+
}
76+
defer f.Close()
77+
78+
reader := csv.NewReader(f)
79+
lines, err := reader.ReadAll()
80+
if err != nil {
81+
return fmt.Errorf("failed to read csv: %w", err)
82+
}
83+
84+
if len(lines) == 0 {
85+
return fmt.Errorf("empty csv file loaded")
86+
}
87+
88+
for i, line := range lines {
89+
if len(line) != 2 {
90+
fmt.Printf("csv row %d has %d cell(s). Skipping to next line", i, len(line))
91+
continue
92+
}
93+
94+
newProblem := Problem{
95+
Question: line[0],
96+
Answer: line[1],
97+
}
98+
99+
p.Questions = append(p.Questions, newProblem)
100+
}
101+
return nil
102+
}
103+
104+
func NewProblemSheet() *ProblemSheet {
105+
return &ProblemSheet{}
106+
}
107+
108+
func (p *ProblemSheet) StartQuiz(limit time.Duration, r io.Reader, w io.Writer) {
109+
110+
reader := bufio.NewReader(r)
111+
112+
fmt.Println(w, "Press Enter to begin quiz")
113+
reader.ReadString('\n')
114+
115+
ctx, cancel := context.WithTimeout(context.Background(), limit)
116+
defer cancel()
117+
118+
for _, problem := range p.Questions {
119+
answerCh := make(chan string, 1)
120+
121+
go func(q string) {
122+
fmt.Fprintf(w, "\n\nQuestion: %s\n", q)
123+
fmt.Fprint(w, "answer: ")
124+
userAns, _ := reader.ReadString('\n')
125+
answerCh <- strings.TrimSpace(userAns)
126+
}(problem.Question)
127+
128+
select {
129+
case userAnswer := <-answerCh:
130+
if userAnswer == problem.Answer {
131+
p.CorrectlyAnswered++
132+
}
133+
case <-ctx.Done():
134+
fmt.Fprintln(w, "\nquiz not completed before timeout")
135+
return
136+
}
137+
}
138+
}
139+
140+
func (p *ProblemSheet) DisplayResults(w io.Writer) {
141+
fmt.Fprintln(w, "Quiz has ended")
142+
fmt.Fprintf(w, "You answered %d/%d questions\n", p.CorrectlyAnswered, len(p.Questions))
143+
}
144+
145+
//type workerFunc func() string
146+
//
147+
//func timeLimit(worker workerFunc, limit time.Duration) (string, error) {
148+
// out := make(chan string, 1)
149+
// ctx, cancel := context.WithTimeout(context.Background(), limit)
150+
// defer cancel()
151+
//
152+
// go func() {
153+
// fmt.Println("goroutine started")
154+
// out <- worker()
155+
// }()
156+
//
157+
// select {
158+
// case result := <-out:
159+
// return result, nil
160+
// case <-ctx.Done():
161+
// return "quiz not completed before timeout", errors.New("work timed out")
162+
// }
163+
//}
164+
165+
//func (p *problemSheet) StartQuiz() string {
166+
// for _, problem := range p.questions {
167+
// fmt.Printf("\n\nQuestion: %s\n", problem.question)
168+
// fmt.Print("answer: ")
169+
// var answer string
170+
// fmt.Scanln(&answer)
171+
//
172+
// if answer == problem.answer {
173+
// p.correctlyAnswered++
174+
// }
175+
// }
176+
//
177+
// return "Quiz completed before timeout"
178+
//}

0 commit comments

Comments
 (0)