Skip to content

Commit

Permalink
Add andreis solution (gophercises#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreis authored and joncalhoun committed Oct 31, 2017
1 parent 9dca4c1 commit 717bb5f
Showing 1 changed file with 137 additions and 0 deletions.
137 changes: 137 additions & 0 deletions students/andreis/main.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 717bb5f

Please sign in to comment.