From d35d6018d5784316a027223c835ee259b90be774 Mon Sep 17 00:00:00 2001 From: hokita Date: Fri, 24 Jul 2020 22:36:18 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E8=AA=B2=E9=A1=8C3-1=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai3-1/hokita/README.md | 54 +++++++++++++ kadai3-1/hokita/go.mod | 3 + kadai3-1/hokita/main.go | 105 ++++++++++++++++++++++++ kadai3-1/hokita/main_test.go | 65 +++++++++++++++ kadai3-1/hokita/profile | 32 ++++++++ kadai3-1/hokita/testdata/words1.txt | 3 + kadai3-1/hokita/testdata/words2.txt | 4 + kadai3-1/hokita/typing.go | 42 ++++++++++ kadai3-1/hokita/typing_test.go | 121 ++++++++++++++++++++++++++++ kadai3-1/hokita/words.txt | 4 + 10 files changed, 433 insertions(+) create mode 100644 kadai3-1/hokita/README.md create mode 100644 kadai3-1/hokita/go.mod create mode 100644 kadai3-1/hokita/main.go create mode 100644 kadai3-1/hokita/main_test.go create mode 100644 kadai3-1/hokita/profile create mode 100644 kadai3-1/hokita/testdata/words1.txt create mode 100644 kadai3-1/hokita/testdata/words2.txt create mode 100644 kadai3-1/hokita/typing.go create mode 100644 kadai3-1/hokita/typing_test.go create mode 100644 kadai3-1/hokita/words.txt diff --git a/kadai3-1/hokita/README.md b/kadai3-1/hokita/README.md new file mode 100644 index 0000000..2fb0009 --- /dev/null +++ b/kadai3-1/hokita/README.md @@ -0,0 +1,54 @@ +# 課題3-1 タイピングゲームを作ろう + +## 課題内容 +- 標準出力に英単語を出す(出すものは自由) +- 標準入力から1行受け取る +- 制限時間内に何問解けたか表示する + +### ヒント +- 制限時間にはtime.After関数を用いる + - context.WithTimeoutでもよい +- select構文を用いる + - 制限時間と入力を同時に待つ + +## 動作 +```shell +$ go build + +$ go build -o typing + +$ ./typing +ddd +>ddd +Good! + +aaa +>aab +Bad.. + +aaa +>aaa +Good! + +bbb +> +------ +Finish!! +Result: 2 points +``` + +## カバレッジ +```shell +$ go test -coverprofile=profile github.com/gopherdojo/dojo8/kadai3-1/hokita/typing +ok github.com/gopherdojo/dojo8/kadai3-1/hokita/typing 0.046s coverage: 46.7% of statements +``` +(低い。。) + +## 工夫したこと +- 入力は「【TRY】チャンネルを使ってみよう」を参考に作成 +- 過去のgopherdojoのレビューコメントを確認してscanner.Scan()のエラー処理を書いた。 + +## わからなかったこと、むずかしかったこと +- `run()`関数の良いテスト方法が思いつかなかった。 + - `input()`のようにテストしやすい単位でメソッドとして外だしをしたかったがこちらも思いつかなったか。 +- エラーハンドリングが合っているか自信がない。 diff --git a/kadai3-1/hokita/go.mod b/kadai3-1/hokita/go.mod new file mode 100644 index 0000000..8d0254e --- /dev/null +++ b/kadai3-1/hokita/go.mod @@ -0,0 +1,3 @@ +module github.com/gopherdojo/dojo8/kadai3-1/hokita/typing + +go 1.14 diff --git a/kadai3-1/hokita/main.go b/kadai3-1/hokita/main.go new file mode 100644 index 0000000..23fb85e --- /dev/null +++ b/kadai3-1/hokita/main.go @@ -0,0 +1,105 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "math/rand" + "os" + "time" +) + +const ( + ExitCodeOK = 0 + ExitCodeError = 1 + + timelimit = 10 + filePath = "./words.txt" +) + +func main() { + rand.Seed(time.Now().UnixNano()) + exitCode := run() + os.Exit(exitCode) +} + +func run() int { + in, errc := input(os.Stdin) + timelimit := time.After(timelimit * time.Second) + + words, err := importWords(filePath) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return ExitCodeError + } + + typing := newTyping(words) + + for { + fmt.Println(typing.word) + fmt.Print(">") + + select { + case word := <-in: + if typing.check(word) { + fmt.Println("Good!") + fmt.Println() + } else { + fmt.Println("Bad..") + fmt.Println() + } + typing.shuffle() + case err := <-errc: + fmt.Println() + fmt.Fprintln(os.Stderr, err) + return ExitCodeError + case <-timelimit: + fmt.Println() + fmt.Println("------") + fmt.Println("Finish!!") + fmt.Printf("Result: %d points\n", typing.getPoint()) + return ExitCodeOK + } + } +} + +func input(r io.Reader) (<-chan string, <-chan error) { + // チャネルを作る + result := make(chan string) + errc := make(chan error) + + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + // チャネルに読み込んだ文字列を送る + result <- s.Text() + if err := s.Err(); err != nil { + errc <- err + } + } + // チャネルを閉じる + close(result) + }() + // チャネルを返す + return result, errc +} + +// cf. https://qiita.com/jpshadowapps/items/ae7274ec0d40882d76b5 +func importWords(filePath string) ([]string, error) { + f, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer f.Close() + + lines := make([]string, 0, 10) + scanner := bufio.NewScanner(f) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + if serr := scanner.Err(); serr != nil { + return nil, err + } + + return lines, nil +} diff --git a/kadai3-1/hokita/main_test.go b/kadai3-1/hokita/main_test.go new file mode 100644 index 0000000..21b3640 --- /dev/null +++ b/kadai3-1/hokita/main_test.go @@ -0,0 +1,65 @@ +package main + +import ( + "bytes" + "reflect" + "testing" +) + +func TestInput(t *testing.T) { + tests := []struct { + name string + in string + want string + }{ + { + name: "match input channel", + in: "hoge", + want: "hoge", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + stdin := bytes.NewBufferString(test.in) + + inc, _ := input(stdin) + + select { + case in := <-inc: + if in != test.want { + t.Errorf(`want="%v" actual="%v"`, test.want, in) + } + } + }) + } +} + +func TestImportWords(t *testing.T) { + tests := []struct { + name string + filepath string + want []string + }{ + { + name: "import testfile1", + filepath: "testdata/words1.txt", + want: []string{"gopher", "golang", "goroutines"}, + }, + { + name: "import testfile2", + filepath: "testdata/words2.txt", + want: []string{"java", "php", "erlang", "elixir"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _ := importWords(test.filepath) + + if !reflect.DeepEqual(got, test.want) { + t.Errorf(`filepath="%v" want="%v" actual="%v"`, test.filepath, test.want, got) + } + }) + } +} diff --git a/kadai3-1/hokita/profile b/kadai3-1/hokita/profile new file mode 100644 index 0000000..488952a --- /dev/null +++ b/kadai3-1/hokita/profile @@ -0,0 +1,32 @@ +mode: set +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:20.13,24.2 3 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:26.16,31.16 4 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:36.2,38.6 2 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:31.16,34.3 2 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:38.6,42.10 3 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:43.21,44.26 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:51.4,51.20 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:52.22,55.24 3 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:56.20,61.21 5 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:44.26,47.5 2 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:47.10,50.5 2 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:66.55,71.12 3 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:84.2,84.21 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:71.12,73.16 2 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:81.3,81.16 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:73.16,76.34 2 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:76.34,78.5 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:88.53,90.16 2 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:93.2,97.21 4 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:100.2,100.40 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:104.2,104.19 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:90.16,92.3 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:97.21,99.3 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:100.40,102.3 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:13.40,21.2 3 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:23.28,25.2 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:27.33,29.2 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:31.42,32.20 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:36.2,36.14 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:32.20,35.3 2 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/typing.go:39.28,42.2 2 1 diff --git a/kadai3-1/hokita/testdata/words1.txt b/kadai3-1/hokita/testdata/words1.txt new file mode 100644 index 0000000..9bbee9f --- /dev/null +++ b/kadai3-1/hokita/testdata/words1.txt @@ -0,0 +1,3 @@ +gopher +golang +goroutines diff --git a/kadai3-1/hokita/testdata/words2.txt b/kadai3-1/hokita/testdata/words2.txt new file mode 100644 index 0000000..f7737e2 --- /dev/null +++ b/kadai3-1/hokita/testdata/words2.txt @@ -0,0 +1,4 @@ +java +php +erlang +elixir diff --git a/kadai3-1/hokita/typing.go b/kadai3-1/hokita/typing.go new file mode 100644 index 0000000..3edbb4c --- /dev/null +++ b/kadai3-1/hokita/typing.go @@ -0,0 +1,42 @@ +package main + +import ( + "math/rand" +) + +type Typing struct { + point int + word string + words []string +} + +func newTyping(words []string) *Typing { + typing := &Typing{ + words: words, + } + + typing.shuffle() + + return typing +} + +func (t *Typing) pointUp() { + t.point += 1 +} + +func (t *Typing) getPoint() int { + return t.point +} + +func (t *Typing) check(word string) bool { + if t.word == word { + t.pointUp() + return true + } + return false +} + +func (t *Typing) shuffle() { + i := rand.Intn(len(t.words)) + t.word = t.words[i] +} diff --git a/kadai3-1/hokita/typing_test.go b/kadai3-1/hokita/typing_test.go new file mode 100644 index 0000000..422875a --- /dev/null +++ b/kadai3-1/hokita/typing_test.go @@ -0,0 +1,121 @@ +package main + +import ( + "math/rand" + "reflect" + "testing" +) + +func TestTyping_newTyping(t *testing.T) { + tests := []struct { + name string + words []string + wantWords []string + }{ + { + name: "initialize", + words: []string{"a", "b"}, + wantWords: []string{"a", "b"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + typing := newTyping(test.words) + + if typing.word == "" { + t.Fatal("did not have shuffled word") + } + + if !reflect.DeepEqual(typing.words, test.wantWords) { + t.Errorf(`want="%v" actual="%v"`, typing.words, test.wantWords) + } + }) + } +} + +func TestTyping_check(t *testing.T) { + tests := []struct { + name string + word string + typedWord string + want bool + wantPoint int + }{ + { + name: "match", + word: "hoge", + typedWord: "hoge", + want: true, + wantPoint: 1, + }, + { + name: "unmatch", + word: "hoge", + typedWord: "fuga", + want: false, + wantPoint: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + typing := &Typing{ + word: test.word, + } + + got := typing.check(test.typedWord) + if got != test.want { + t.Errorf( + `word="%v" typedWord="%v" want="%v" got="%v"`, + test.word, test.typedWord, test.want, got, + ) + } + + if typing.point != test.wantPoint { + t.Errorf( + `word="%v" typedWord="%v" wantPoint="%v" acutal="%v"`, + test.word, test.typedWord, test.wantPoint, typing.point, + ) + } + }) + } +} + +func TestTyping_shuffle(t *testing.T) { + tests := []struct { + name string + seed int64 + want string + }{ + { + name: "randseed1", + seed: 1, + want: "c", + }, + { + name: "randseed2", + seed: 2, + want: "b", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + rand.Seed(test.seed) + + typing := &Typing{ + words: []string{"a", "b", "c"}, + } + + typing.shuffle() + + if typing.word != test.want { + t.Errorf( + `seed="%v" want="%v" actual="%v"`, + test.seed, test.want, typing.word, + ) + } + }) + } +} diff --git a/kadai3-1/hokita/words.txt b/kadai3-1/hokita/words.txt new file mode 100644 index 0000000..35fbd83 --- /dev/null +++ b/kadai3-1/hokita/words.txt @@ -0,0 +1,4 @@ +aaa +bbb +ccc +ddd From 6b116dd1b2355a715f77ab5616bbe19e2b15ab77 Mon Sep 17 00:00:00 2001 From: hokita Date: Sat, 25 Jul 2020 12:43:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E3=83=90=E3=82=B0=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E3=81=A8=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=83=91=E3=82=B9?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E6=96=B9=E6=B3=95=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai3-1/hokita/main.go | 8 ++++---- kadai3-1/hokita/main_test.go | 5 +++-- kadai3-1/hokita/profile | 5 +++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/kadai3-1/hokita/main.go b/kadai3-1/hokita/main.go index 23fb85e..013ca83 100644 --- a/kadai3-1/hokita/main.go +++ b/kadai3-1/hokita/main.go @@ -14,7 +14,7 @@ const ( ExitCodeError = 1 timelimit = 10 - filePath = "./words.txt" + filePath = "words.txt" ) func main() { @@ -73,9 +73,9 @@ func input(r io.Reader) (<-chan string, <-chan error) { for s.Scan() { // チャネルに読み込んだ文字列を送る result <- s.Text() - if err := s.Err(); err != nil { - errc <- err - } + } + if err := s.Err(); err != nil { + errc <- err } // チャネルを閉じる close(result) diff --git a/kadai3-1/hokita/main_test.go b/kadai3-1/hokita/main_test.go index 21b3640..deb01de 100644 --- a/kadai3-1/hokita/main_test.go +++ b/kadai3-1/hokita/main_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "path/filepath" "reflect" "testing" ) @@ -43,12 +44,12 @@ func TestImportWords(t *testing.T) { }{ { name: "import testfile1", - filepath: "testdata/words1.txt", + filepath: filepath.Join("testdata", "words1.txt"), want: []string{"gopher", "golang", "goroutines"}, }, { name: "import testfile2", - filepath: "testdata/words2.txt", + filepath: filepath.Join("testdata", "words2.txt"), want: []string{"java", "php", "erlang", "elixir"}, }, } diff --git a/kadai3-1/hokita/profile b/kadai3-1/hokita/profile index 488952a..755a533 100644 --- a/kadai3-1/hokita/profile +++ b/kadai3-1/hokita/profile @@ -13,9 +13,10 @@ github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:47.10,50.5 2 0 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:66.55,71.12 3 1 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:84.2,84.21 1 1 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:71.12,73.16 2 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:77.3,77.33 1 1 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:81.3,81.16 1 1 -github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:73.16,76.34 2 1 -github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:76.34,78.5 1 0 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:73.16,76.4 1 1 +github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:77.33,79.4 1 0 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:88.53,90.16 2 1 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:93.2,97.21 4 1 github.com/gopherdojo/dojo8/kadai3-1/hokita/typing/main.go:100.2,100.40 1 1