diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e529828 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +testdata + diff --git a/README.md b/README.md index f19aaef..9722074 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,8 @@ -# dojo7 -#7 Gopher道場用のリポジトリです -connpass: https://gopherdojo.connpass.com/event/142892/ +# 課題3 -## 課題の提出方法 - -1回目の課題を提出する場合は次のようにコードを書いて下さい。 - -* ブランチ名を`kadai1-tenntenn`のようにする -* `kadai1/tenntenn`のようにディレクトリを作る -* READMEに説明や文章による課題の回答を書く -* PRを送る - -※FBには時間がかかる可能性があります。 +## タイピングゲームを作ろう +- [x] 標準出力に英単語を出す(出すものは自由) +- [x] 標準入力から1行受け取る +- [x] 制限時間内に何問解けたか表示する diff --git a/kadai1/.gitkeep b/kadai1/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/kadai3-1/shinta/export_test.go b/kadai3-1/shinta/export_test.go new file mode 100644 index 0000000..5d70d0f --- /dev/null +++ b/kadai3-1/shinta/export_test.go @@ -0,0 +1,4 @@ +package main + +var Execute = execute +var InputRoutine = inputRoutine diff --git a/kadai3-1/shinta/go.mod b/kadai3-1/shinta/go.mod new file mode 100644 index 0000000..f56eb14 --- /dev/null +++ b/kadai3-1/shinta/go.mod @@ -0,0 +1,3 @@ +module github.com/gopherdojo/dojo7/kadai3-1/shinta + +go 1.12 diff --git a/kadai3-1/shinta/go.sum b/kadai3-1/shinta/go.sum new file mode 100644 index 0000000..5726ce0 --- /dev/null +++ b/kadai3-1/shinta/go.sum @@ -0,0 +1 @@ +github.com/gopherdojo/dojo7 v0.0.0-20190903074013-69385d40c994 h1:UbdhtSFDdFiSYOb/TkEmlRIUFQRrBlKOzVDY3+SXaSw= diff --git a/kadai3-1/shinta/main.go b/kadai3-1/shinta/main.go new file mode 100644 index 0000000..d995334 --- /dev/null +++ b/kadai3-1/shinta/main.go @@ -0,0 +1,66 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "time" + + "github.com/gopherdojo/dojo7/kadai3-1/shinta/typing" +) + +const timeLimit = 5 + +/* +Typing displays the English word in question with the showtext method. +Compare with the value entered in the judge method. +*/ +type Typing interface { + ShowText() string + Judge(input string) bool +} + +func main() { + problems := []string{"apple", "bake", "cup", "dog", "egg", "fight", "green", "hoge", "idea", "japan"} + typing := typing.Redy(problems) + chInput := inputRoutine(os.Stdin) + chFinish := time.After(time.Duration(timeLimit) * time.Second) + + execute(chInput, chFinish, os.Stdout, typing) +} + +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.ShowText()) + fmt.Fprint(stdout, "type>>") + select { + case inText := <-chInput: + if t.Judge(inText) { + 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-1/shinta/main_mock_test.go b/kadai3-1/shinta/main_mock_test.go new file mode 100644 index 0000000..4676029 --- /dev/null +++ b/kadai3-1/shinta/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) ShowText() string { + return "FOO" +} + +func (typ *TypingMock) Judge(input string) bool { + return "FOO" == input +} diff --git a/kadai3-1/shinta/main_test.go b/kadai3-1/shinta/main_test.go new file mode 100644 index 0000000..8a50283 --- /dev/null +++ b/kadai3-1/shinta/main_test.go @@ -0,0 +1,79 @@ +package main_test + +import ( + "bytes" + "testing" + "time" + + main "github.com/gopherdojo/dojo7/kadai3-1/shinta" +) + +func TestInputRoutine(t *testing.T) { + input := []string{"apple", "bake", "cup", "dog"} + // StdinMockのinputに、標準入力で送信されたと仮定した文字列が入る + 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: "apple", + }, + { + inputText: "bbaak", + }, + { + inputText: "cup", + }, + { + time: time.Now(), + }, + } + + // 新しく文字列を格納するbufferを確保 + buf := bytes.NewBufferString("") + typ := &TypingMock{} + + go func() { + for _, s := range scenario { + time.Sleep(100 * time.Millisecond) + if s.inputText != "" { + chInput <- s.inputText + } + if !s.time.IsZero() { + chFinish <- s.time + } + } + }() + main.Execute(chInput, chFinish, buf, typ) + + expected := []byte("" + + "[001]: apple\n" + "type>>" + "Correct!\n" + + "[002]: bake\n" + "type>>" + "Miss!\n" + + "[003]: cup\n" + "type>>" + "Correct!\n" + + "[004]: dog\n" + "type>>" + + "\nTime's up!!\n" + + "You Scored: 2\n") + + // byteスライスの比較、a == bの場合は0を返す + if bytes.Compare(buf.Bytes(), expected) != 0 { + t.Errorf("[expected]:\n%s\n[actual]:\n%s", expected, buf.Bytes()) + } +} diff --git a/kadai3-1/shinta/typing/typing.go b/kadai3-1/shinta/typing/typing.go new file mode 100644 index 0000000..765cbbe --- /dev/null +++ b/kadai3-1/shinta/typing/typing.go @@ -0,0 +1,33 @@ +package typing + +import ( + "math/rand" + "time" +) + +// Typing represents a list of English words and a single word extracted from it. +type Typing struct { + wordList []string + nextWord string +} + +// Redy function is a constructor for typing struct. +func Redy(prolems []string) *Typing { + // 乱数の初期化 + rand.Seed(time.Now().UnixNano()) + return &Typing{ + wordList: prolems, + } +} + +// ShowText method returns one English word randomly from the English word list. +func (t *Typing) ShowText() string { + i := rand.Intn(len(t.wordList)) + t.nextWord = t.wordList[i] + return t.nextWord +} + +// Judge method determines whether the sent word and the nextText of the typing structure are the same +func (t *Typing) Judge(inText string) bool { + return inText == t.nextWord +} diff --git a/kadai3-1/shinta/typing/typing_test.go b/kadai3-1/shinta/typing/typing_test.go new file mode 100644 index 0000000..da7dae5 --- /dev/null +++ b/kadai3-1/shinta/typing/typing_test.go @@ -0,0 +1,46 @@ +package typing_test + +import ( + "testing" + + "github.com/gopherdojo/dojo7/kadai3-1/shinta/typing" +) + +var problems = []string{"apple", "bake", "cup", "dog", "egg", "fight", "green", "hoge", "idea", "japan"} + +func includes(s string) bool { + for _, v := range problems { + if v == s { + return true + } + } + return false +} + +func TestShowText(t *testing.T) { + typ := typing.Redy(problems) + for i := 0; i < len(problems); i++ { + txt := typ.ShowText() + if !includes(txt) { + t.Errorf("actual: %v\n", txt) + } + } +} + +func TestJudge(t *testing.T) { + typ := typing.Redy(problems) + txt := typ.ShowText() + + if !typ.Judge(txt) { + t.Errorf("Judge() must be true") + } +} + +func TestJudgeFailed(t *testing.T) { + typ := typing.Redy(problems) + typ.ShowText() + + if typ.Judge("TTT") { + t.Errorf("Judge() must be false") + } +}