Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hokita / 課題3-1 #19

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions kadai3-1/hokita/README.md
Original file line number Diff line number Diff line change
@@ -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()`のようにテストしやすい単位でメソッドとして外だしをしたかったがこちらも思いつかなったか。
- エラーハンドリングが合っているか自信がない。
3 changes: 3 additions & 0 deletions kadai3-1/hokita/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/gopherdojo/dojo8/kadai3-1/hokita/typing

go 1.14
105 changes: 105 additions & 0 deletions kadai3-1/hokita/main.go
Original file line number Diff line number Diff line change
@@ -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
}
66 changes: 66 additions & 0 deletions kadai3-1/hokita/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"bytes"
"path/filepath"
"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: filepath.Join("testdata", "words1.txt"),
want: []string{"gopher", "golang", "goroutines"},
},
{
name: "import testfile2",
filepath: filepath.Join("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)
}
})
}
}
33 changes: 33 additions & 0 deletions kadai3-1/hokita/profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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: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.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
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
3 changes: 3 additions & 0 deletions kadai3-1/hokita/testdata/words1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gopher
golang
goroutines
4 changes: 4 additions & 0 deletions kadai3-1/hokita/testdata/words2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
java
php
erlang
elixir
42 changes: 42 additions & 0 deletions kadai3-1/hokita/typing.go
Original file line number Diff line number Diff line change
@@ -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]
}
Loading