Implement creating new games
This commit is contained in:
120
pkg/gameCreator/gameCreator.go
Normal file
120
pkg/gameCreator/gameCreator.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package gameCreator
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreateTemplate(w io.Writer, questions uint64, choicesPerQuestion uint64) (retE error) {
|
||||
csvW := csv.NewWriter(w)
|
||||
defer func() {
|
||||
csvW.Flush()
|
||||
if err := csvW.Error(); err != nil && retE != nil {
|
||||
retE = err
|
||||
}
|
||||
}()
|
||||
|
||||
for i := uint64(0); i < questions; i++ {
|
||||
var length string
|
||||
if i == 0 {
|
||||
length = "10000"
|
||||
}
|
||||
if err := csvW.Write([]string{"Nadpis otázky", length, ""}); err != nil {
|
||||
return err
|
||||
}
|
||||
for j := uint64(0); j < choicesPerQuestion; j++ {
|
||||
var correct string
|
||||
if j == 0 {
|
||||
correct = "1"
|
||||
}
|
||||
if err := csvW.Write([]string{"", "Nadpis možnosti", correct}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
Questions []Question
|
||||
}
|
||||
|
||||
type Question struct {
|
||||
Title string
|
||||
Choices []Choice
|
||||
Length uint64
|
||||
}
|
||||
|
||||
type Choice struct {
|
||||
Title string
|
||||
Correct bool
|
||||
}
|
||||
|
||||
var ErrTooManyQuestions = errors.New("there were questions above the limit")
|
||||
var ErrTooManyChoices = errors.New("there were choices above the limit")
|
||||
var ErrInvalidSyntax = errors.New("")
|
||||
|
||||
func Parse(r io.Reader, maxQuestions uint64, maxChoicesPerQuestion uint64) (Game, error) {
|
||||
var g Game
|
||||
var csvR = csv.NewReader(r)
|
||||
csvR.FieldsPerRecord = 3
|
||||
csvR.TrimLeadingSpace = true
|
||||
var questions, choices uint64
|
||||
for {
|
||||
if row, err := csvR.Read(); err == nil {
|
||||
if row[0] == "" && row[1] == "" && row[2] == "" {
|
||||
continue
|
||||
} else if row[0] == "" {
|
||||
choices++
|
||||
if questions == 0 {
|
||||
return g, ErrInvalidSyntax
|
||||
}
|
||||
if choices > maxChoicesPerQuestion {
|
||||
return g, ErrTooManyChoices
|
||||
}
|
||||
var correct bool
|
||||
if row[2] == "1" {
|
||||
correct = true
|
||||
}
|
||||
g.Questions[len(g.Questions)-1].Choices = append(g.Questions[len(g.Questions)-1].Choices, Choice{
|
||||
Title: row[1],
|
||||
Correct: correct,
|
||||
})
|
||||
} else {
|
||||
questions++
|
||||
choices = 0
|
||||
if questions > maxQuestions {
|
||||
return g, ErrTooManyQuestions
|
||||
}
|
||||
var length uint64
|
||||
if row[1] != "" {
|
||||
if l, err := strconv.ParseUint(row[1], 10, 64); err == nil {
|
||||
length = l
|
||||
} else {
|
||||
return g, ErrInvalidSyntax
|
||||
}
|
||||
} else {
|
||||
if questions > 1 {
|
||||
length = g.Questions[len(g.Questions)-1].Length
|
||||
} else {
|
||||
length = uint64((10 * time.Second).Milliseconds())
|
||||
}
|
||||
}
|
||||
g.Questions = append(g.Questions, Question{
|
||||
Title: row[0],
|
||||
Length: length,
|
||||
})
|
||||
}
|
||||
} else if err == io.EOF {
|
||||
break
|
||||
} else if err == csv.ErrFieldCount {
|
||||
return g, ErrInvalidSyntax
|
||||
} else {
|
||||
return g, err
|
||||
}
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
66
pkg/gameCreator/gameCreator_test.go
Normal file
66
pkg/gameCreator/gameCreator_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package gameCreator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateTemplate(t *testing.T) {
|
||||
const expected = "Nadpis otázky,10000,\n,Nadpis možnosti,1\n,Nadpis možnosti,\n,Nadpis možnosti,\n,Nadpis možnosti,\n" +
|
||||
"Nadpis otázky,,\n,Nadpis možnosti,1\n,Nadpis možnosti,\n,Nadpis možnosti,\n,Nadpis možnosti,\n" +
|
||||
"Nadpis otázky,,\n,Nadpis možnosti,1\n,Nadpis možnosti,\n,Nadpis možnosti,\n,Nadpis možnosti,\n" +
|
||||
"Nadpis otázky,,\n,Nadpis možnosti,1\n,Nadpis možnosti,\n,Nadpis možnosti,\n,Nadpis možnosti,\n" +
|
||||
"Nadpis otázky,,\n,Nadpis možnosti,1\n,Nadpis možnosti,\n,Nadpis možnosti,\n,Nadpis možnosti,\n"
|
||||
var actual bytes.Buffer
|
||||
actual.Grow(len(expected))
|
||||
if err := CreateTemplate(&actual, 5, 4); err != nil {
|
||||
t.Fatalf("Unexpected error returned from CreateTemplate: %v", err)
|
||||
}
|
||||
if act := actual.String(); act != expected {
|
||||
t.Fatalf("Wrong template generated. Expected:\n%s\n\nGot:\n%s\n", expected, act)
|
||||
}
|
||||
}
|
||||
func TestParse(t *testing.T) {
|
||||
const input = "H2O is,3000,\n,Gasoline,\n,Salt,\n,Water,1\n" +
|
||||
"π is rational,,\n,Yes,\n,No,1\n" +
|
||||
"IPv4 address length is,5000,\n,8b,\n,16b,\n,32b,1\n,64b,\n,128b,\n"
|
||||
var expected = Game{
|
||||
Questions: []Question{
|
||||
{
|
||||
Title: "H2O is",
|
||||
Length: 3000,
|
||||
Choices: []Choice{
|
||||
{Title: "Gasoline"},
|
||||
{Title: "Salt"},
|
||||
{Title: "Water", Correct: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "π is rational",
|
||||
Length: 3000,
|
||||
Choices: []Choice{
|
||||
{Title: "Yes"},
|
||||
{Title: "No", Correct: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "IPv4 address length is",
|
||||
Length: 5000,
|
||||
Choices: []Choice{
|
||||
{Title: "8b"},
|
||||
{Title: "16b"},
|
||||
{Title: "32b", Correct: true},
|
||||
{Title: "64b"},
|
||||
{Title: "128b"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if g, err := Parse(strings.NewReader(input), 10, 10); err == nil && !reflect.DeepEqual(g, expected) {
|
||||
t.Fatalf("Parse:\n\tActual: %#v\n\tExpected: %#v", g, expected)
|
||||
} else if err != nil {
|
||||
t.Fatalf("Unexpected error from Parse: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user