diff --git a/kadai3/en-ken/kadai3/export_test.go b/kadai3/en-ken/kadai3/export_test.go new file mode 100644 index 0000000..45d8f27 --- /dev/null +++ b/kadai3/en-ken/kadai3/export_test.go @@ -0,0 +1,5 @@ +package main + +var Execute = execute + +var InputRoutine = inputRoutine diff --git a/kadai3/en-ken/kadai3/main.go b/kadai3/en-ken/kadai3/main.go new file mode 100644 index 0000000..29865b2 --- /dev/null +++ b/kadai3/en-ken/kadai3/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "time" + + typing "github.com/gopherdojo/dojo6/kadai3/en-ken" +) + +func main() { + const timeoutSec = 10 + textDict := []string{"foo", "bar", "baz", "qux"} + t := typing.NewTyping(textDict) + + chInput := inputRoutine(os.Stdin) + chFinish := time.After(time.Duration(timeoutSec) * time.Second) + + execute(chInput, chFinish, os.Stdout, t) +} + +// Typing is interface to typing.Typing +type Typing interface { + GetNextText() string + IsCorrect(input string) bool +} + +func execute(chInput <-chan string, chFinish <-chan time.Time, stdout io.Writer, t Typing) { + + score := 0 + for i := 1; ; i++ { + fmt.Fprintf(stdout, "[%03d]: %v\n", i, t.GetNextText()) + fmt.Fprint(stdout, "type>>") + select { + case text := <-chInput: + if t.IsCorrect(text) { + score++ + fmt.Fprintln(stdout, "Correct!") + } else { + fmt.Fprintln(stdout, "Miss!") + } + case <-chFinish: + fmt.Fprintln(stdout, "\nTime's up!!") + fmt.Fprintf(stdout, "You Scored: %v\n", score) + return + } + } +} + +func inputRoutine(r io.Reader) <-chan string { + ch := make(chan string) + + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + ch <- s.Text() + } + }() + + return ch +} diff --git a/kadai3/en-ken/kadai3/main_mock_test.go b/kadai3/en-ken/kadai3/main_mock_test.go new file mode 100644 index 0000000..c515828 --- /dev/null +++ b/kadai3/en-ken/kadai3/main_mock_test.go @@ -0,0 +1,44 @@ +package main_test + +import ( + "io" +) + +//Stdin +type StdinMock struct { + i int + input []string +} + +func (stdin *StdinMock) Read(p []byte) (n int, err error) { + if stdin.i >= len(stdin.input) { + return 0, io.EOF + } + b := []byte(stdin.input[stdin.i] + "\n") //Scanが回るようにLF追加 + copy(p, b) + stdin.i++ + return len(b), nil +} + +//Stdout +type StdoutMock struct { + output []string +} + +func (stdout *StdoutMock) Write(p []byte) (n int, err error) { + str := string(p) + stdout.output = append(stdout.output, str) + return len(str), nil +} + +//Typing +type TypingMock struct { +} + +func (typ *TypingMock) GetNextText() string { + return "FOO" +} + +func (typ *TypingMock) IsCorrect(input string) bool { + return "FOO" == input +} diff --git a/kadai3/en-ken/kadai3/main_test.go b/kadai3/en-ken/kadai3/main_test.go new file mode 100644 index 0000000..6d7efab --- /dev/null +++ b/kadai3/en-ken/kadai3/main_test.go @@ -0,0 +1,77 @@ +package main_test + +import ( + "bytes" + "testing" + "time" + + main "github.com/gopherdojo/dojo6/kadai3/en-ken/kadai3" +) + +func TestInputRoutine(t *testing.T) { + input := []string{"foo", "bar", "baz", "qux"} + stdin := &StdinMock{ + i: 0, + input: input, + } + + ch := main.InputRoutine(stdin) + + for _, expected := range input { + actual := <-ch + if actual != expected { + t.Errorf("expected:%v, actual:%v", expected, actual) + } + } +} + +func TestExecute(t *testing.T) { + chInput := make(chan string, 3) + chFinish := make(chan time.Time, 1) + + scenario := []struct { + inputText string + time time.Time + }{ + { + inputText: "FOO", + }, + { + inputText: "BAR", + }, + { + inputText: "FOO", + }, + { + time: time.Now(), + }, + } + + buf := bytes.NewBufferString("") + typ := &TypingMock{} + + go func() { + for _, s := range scenario { + time.Sleep(100 * time.Millisecond) //DASAI + if s.inputText != "" { + chInput <- s.inputText + } + if !s.time.IsZero() { + chFinish <- s.time + } + } + }() + main.Execute(chInput, chFinish, buf, typ) + + expected := []byte("" + + "[001]: FOO\n" + "type>>" + "Correct!\n" + + "[002]: FOO\n" + "type>>" + "Miss!\n" + + "[003]: FOO\n" + "type>>" + "Correct!\n" + + "[004]: FOO\n" + "type>>" + + "\nTime's up!!\n" + + "You Scored: 2\n") + + if bytes.Compare(buf.Bytes(), expected) != 0 { + t.Errorf("[expected]:\n%s\n[actual]:\n%s", expected, buf.Bytes()) + } +} diff --git a/kadai3/en-ken/readme.md b/kadai3/en-ken/readme.md new file mode 100644 index 0000000..4b498da --- /dev/null +++ b/kadai3/en-ken/readme.md @@ -0,0 +1,14 @@ +# 課題3 + +## タイピングゲームを作ろう + +- [x] 標準出力に英単語を出す(出すものは自由) +- [x] 標準入力から1行受け取る +- [x] 制限時間内に何問解けたか表示する + +## 使い方 + +```go +go get github.com/gopherdojo/dojo6/kadai3/en-ken/kadai3 +kadai3 +``` diff --git a/kadai3/en-ken/typing.go b/kadai3/en-ken/typing.go new file mode 100644 index 0000000..d1286ae --- /dev/null +++ b/kadai3/en-ken/typing.go @@ -0,0 +1,33 @@ +package typing + +import ( + "math/rand" + "time" +) + +// Typing is the class to judge input +type Typing struct { + dict []string + nextText string +} + +// NewTyping is a constructor +func NewTyping(textDict []string) *Typing { + rand.Seed(time.Now().UnixNano()) + + return &Typing{ + dict: textDict, + } +} + +// GetNextText returns next text +func (t *Typing) GetNextText() string { + i := rand.Int() % len(t.dict) + t.nextText = t.dict[i] + return t.nextText +} + +// IsCorrect judges if input is correct or not. +func (t *Typing) IsCorrect(inputText string) bool { + return t.nextText == inputText +} diff --git a/kadai3/en-ken/typing_test.go b/kadai3/en-ken/typing_test.go new file mode 100644 index 0000000..39237a6 --- /dev/null +++ b/kadai3/en-ken/typing_test.go @@ -0,0 +1,46 @@ +package typing_test + +import ( + "testing" + + typing "github.com/gopherdojo/dojo6/kadai3/en-ken" +) + +var dict = []string{"ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VWX", "YZ"} + +func contains(s string) bool { + for _, v := range dict { + if v == s { + return true + } + } + return false +} + +func TestTypingCanGetNextText(t *testing.T) { + typ := typing.NewTyping(dict) + for i := 0; i < 100; i++ { + txt := typ.GetNextText() + if !contains(txt) { + t.Errorf("actual: %v\n", txt) + } + } +} + +func TestTypingIsCorrect(t *testing.T) { + typ := typing.NewTyping(dict) + txt := typ.GetNextText() + + if !typ.IsCorrect(txt) { + t.Errorf("IsCorrect() must be true") + } +} + +func TestTypingIsCorrectFailed(t *testing.T) { + typ := typing.NewTyping(dict) + typ.GetNextText() + + if typ.IsCorrect("YZZ") { + t.Errorf("IsCorrect() must be false") + } +}