Skip to content

Kadai3 tomoyuki.kobayashi #36

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

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8a7dcf1
add kadai1 files :lol:
Nov 8, 2018
ab31386
add todos
Nov 8, 2018
ef36126
add kadai2 files
Nov 17, 2018
c9587ee
Delete .gitignore
bakisunsan Nov 17, 2018
e69b664
Delete Makefile
bakisunsan Nov 17, 2018
9e5a807
Delete README.md
bakisunsan Nov 17, 2018
f9f7c4e
Delete main.go
bakisunsan Nov 17, 2018
4bf0dd9
Delete file_finder.go
bakisunsan Nov 17, 2018
71569f9
Delete formats.go
bakisunsan Nov 17, 2018
4cec624
Delete formats_test.go
bakisunsan Nov 17, 2018
4458643
Delete image_converter.go
bakisunsan Nov 17, 2018
d7df320
Update main.go
bakisunsan Nov 18, 2018
e5de4ee
add load question logics
Nov 21, 2018
06ad2ec
とりあえず一通り動くバージョン
Nov 22, 2018
2abbf61
コメント修正
Nov 22, 2018
3e212f5
Delete Makefile
bakisunsan Nov 22, 2018
8bfcc95
Delete README.md
bakisunsan Nov 22, 2018
1b37ffa
Delete file_finder.go
bakisunsan Nov 22, 2018
788ceb5
Delete file_finder_test.go
bakisunsan Nov 22, 2018
bf5cb5e
Delete formats.go
bakisunsan Nov 22, 2018
26db9b9
Delete formats_test.go
bakisunsan Nov 22, 2018
74dd45a
Delete image_converter.go
bakisunsan Nov 22, 2018
c074309
Delete image_converter_test.go
bakisunsan Nov 22, 2018
d8e8288
Delete main.go
bakisunsan Nov 22, 2018
06c5785
Delete main_test.go
bakisunsan Nov 22, 2018
00001a7
Update Makefile
bakisunsan Nov 22, 2018
4f8b436
refactor game
Nov 22, 2018
89975a8
リファクタリングとテスト追加
Nov 22, 2018
feb6bd9
Merge branch 'kadai3-tomoyuki.kobayashi' of https://github.com/bakisu…
Nov 22, 2018
4b10c87
rename
Nov 22, 2018
3dbe9fb
add test
Nov 22, 2018
5decc01
rangeの動作確認ができてる版
Nov 23, 2018
1a4401c
rangeダウンロードできる版
Nov 24, 2018
d4abbe7
work version
Nov 24, 2018
ce761c1
work version
Nov 24, 2018
7a6cd63
Delete file4.txt
bakisunsan Nov 24, 2018
28b3f22
Delete invalid.jpg
bakisunsan Nov 24, 2018
acefdc7
ファイルクローズが漏れていたので追加
Nov 24, 2018
847d7c4
Merge branch 'kadai3-tomoyuki.kobayashi' of https://github.com/bakisu…
Nov 24, 2018
e06f9a4
add defer
Nov 25, 2018
67258fe
fix for review comments
Nov 27, 2018
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
Binary file added kadai2/src/tomoyukikobayashi/testdata/file1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/src/tomoyukikobayashi/testdata/file2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/src/tomoyukikobayashi/testdata/file3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions kadai3-1/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.PHONY: deps
deps:
go get github.com/golang/lint/golint

.PHONY: build
build:
go build -o type tomoyukikobayashi

.PHONY: test
test:
go test -v -cover ./...

.PHONY: cover
cover:
go test -coverprofile=mainprof tomoyukikobayashi
go tool cover -html=mainprof

.PHONY: lint
lint: deps
go vet ./...
golint ./...

.PHONY: fmt
fmt: deps
go fmt *.go
25 changes: 25 additions & 0 deletions kadai3-1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
GoTypingGame
=====

# Overview

最高にいけてる楽しいタイピングゲーム
Goで書かれている

# SetUp

下記のようにコマンドを叩くと、実行形式のtypeファイルが生成されます
```
make build
```

# Usage
```
type [OPTION]
```
オプション
```
Usage of typing:
-t int
time to play (second) default=30s (default 30)
```
102 changes: 102 additions & 0 deletions kadai3-1/src/tomoyukikobayashi/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Pacakge main is the entry point of this project.
This mainly provides interaction logics and parameters
used in CLI intrerfaces.
*/
package main

import (
"context"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"time"

"tomoyukikobayashi/typing"
)

const (
wordFile = "words.yaml"
)

// CLIのExitコード
const (
ExitSuccess = 0
ExitError = 1
ExitInvalidArgs = 2
)

// Exitしてもテスト落ちない操作するようにエイリアスにしている
var exit = os.Exit

// CLI テストしやすいようにCLIの出力先を差し替えられるようにしている
type CLI struct {
inStream io.Reader
outStream io.Writer
errStream io.Writer
}

// CLIツールのエントリーポイント
func main() {
cli := &CLI{inStream: os.Stdin, outStream: os.Stdout, errStream: os.Stderr}
exit(cli.Run(os.Args))
}

// Run テスト用に実行ロジックを切り出した内容
func (c *CLI) Run(args []string) int {

flags := flag.NewFlagSet("typing", flag.ContinueOnError)
flags.SetOutput(c.errStream)

var t int
flags.IntVar(&t, "t", 30, "time to play (second) default=30s")

if err := flags.Parse(args[1:]); err != nil {
return ExitInvalidArgs
}

// yamlファイルから語彙リストを読み出す
cur, _ := os.Getwd()
file, err := os.Open(filepath.Join(cur, wordFile))
if err != nil {
fmt.Fprintf(c.outStream, "failed to initizalize game %v", err)
return ExitError
}
// クローズできなくても実害ないので、エラー処理は省略
defer file.Close()

// gameを動作させるインターフェイスを初期化
game, err := typing.NewGame(file, c.inStream)
if err != nil {
fmt.Fprintf(c.outStream, "failed to initizalize game %v", err)
return ExitError
}

fmt.Fprintf(c.outStream, "start game %d sec\n", t)
tc := time.Duration(t) * time.Second
ctx, cancel := context.WithTimeout(context.Background(), tc)
defer cancel()
qCh, aCh, rCh := game.Run(ctx)

for {
q, progress := <-qCh
fmt.Fprintf(c.outStream, "%v\n", q)
if !progress {
break
}

fmt.Fprintf(c.outStream, ">")
a, progress := <-aCh
fmt.Fprintf(c.outStream, "%v\n", a)
if !progress {
break
}
}

r := <-rCh
fmt.Fprintf(c.outStream, "clear %v miss %v\n", r[0], r[1])

return ExitSuccess
}
108 changes: 108 additions & 0 deletions kadai3-1/src/tomoyukikobayashi/typing/game.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package typing

import (
"bufio"
"context"
"io"
)

// Game タイピングゲームを制御するロジックを返す
type Game interface {
Run(context.Context) (question <-chan string, answer <-chan string, result <-chan [2]int)
}

type constGame struct {
Questioner
input io.Reader
// NOTE コンテキストにゲーム状態格納しようとしたがコピーして作り直すから、途中で書き換えてもルーチンをまたいでシェアされない(親子関係で)
// 結局共有変数に書いていることになるので、脆弱感がすごい
clear int
miss int
currentWord string
}

// NewGame Gameのコンストラクタです
func NewGame(source, input io.Reader) (Game, error) {
// クイズデータを読み込む
d, err := NewQuizData(source)
if err != nil {
return nil, err
}
q := NewQuestioner(d)
return &constGame{Questioner: q, input: input}, nil
}

// Run ゲームを開始する
func (c *constGame) Run(ctx context.Context) (<-chan string, <-chan string, <-chan [2]int) {
// TODO routine数にあわせてサイズ調整は死ねるのでonce.DO が使えるかも
routines := 2
rCh := make(chan [2]int, routines)

qCh := c.question(ctx, rCh)
aCh := c.answer(ctx, rCh)

return qCh, aCh, rCh
}

// 問題をqChに送る
func (c *constGame) question(ctx context.Context, rCh chan<- [2]int) <-chan string {
qCh := make(chan string)
go func() {
for {
word := c.GetNewWord(c.nextLevel())
select {
case qCh <- word:
c.currentWord = word
case <-ctx.Done():
rCh <- [2]int{c.clear, c.miss}
close(qCh)
return
}
}
}()
return qCh
}

// 回答をストリームから読み込みしてaChに送る
func (c *constGame) answer(ctx context.Context, rCh chan<- [2]int) <-chan string {
sc := bufio.NewScanner(c.input)
aCh := make(chan string)
go func() {
for {
if !sc.Scan() {
continue
}
ans := sc.Text()
select {
case aCh <- ans:
if c.isCorrect(ans) {
c.clear = c.clear + 1
} else {
c.miss = c.miss + 1
}
// contextがtimeoutしたら結果を返却
case <-ctx.Done():
rCh <- [2]int{c.clear, c.miss}
close(aCh)
return
}
}
}()
return aCh
}

// ワードの比較
func (c *constGame) isCorrect(word string) bool {
return c.currentWord == word
}

// HACK 成功した回数に応じて、使う語彙のレベルを決める。ここは決め打ちで書いてる
func (c *constGame) nextLevel() int {
if c.clear < 10 {
return 1
}
if c.clear < 20 {
return 2
}
return 3
}
125 changes: 125 additions & 0 deletions kadai3-1/src/tomoyukikobayashi/typing/game_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package typing

import (
"context"
"io"
"os"
"strings"
"testing"
"time"
)

func Test_NewGame(t *testing.T) {
tests := []struct {
name string
source io.Reader
hasErr bool
}{
{
name: "valid",
source: strings.NewReader(`
Level1:
- hoge

Level2:
- difficult

Level3:
- test`),
hasErr: false,
},
{
name: "invalid",
source: strings.NewReader(``),
hasErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := NewGame(tt.source, os.Stdin)
if err != nil && !tt.hasErr {
t.Fatalf("got err = %#v", err)
}
})
}
}

func Test_Run(t *testing.T) {
tests := []struct {
name string
source io.Reader
input io.Reader
hasErr bool
}{
{
name: "valid",
source: strings.NewReader(`
Level1:
- hoge

Level2:
- difficult

Level3:
- testtestsete
`),
input: strings.NewReader(`hoge
hoge
hoge
hoge
hoge
hoge
hoge
hoge
miss
hoge
miss
hoge
difficult
difficult
`),
hasErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
game, err := NewGame(tt.source, tt.input)
if err != nil {
t.Fatalf("initialize game failed %v", game)
}

tc := time.Duration(100) * time.Millisecond
ctx, cancel := context.WithTimeout(context.Background(), tc)
defer cancel()

var want [2]int
qCh, aCh, rCh := game.Run(ctx)
var tmpQ, tmpA string
for {
select {
case a := <-aCh:
t.Errorf("a %v\n", a)
tmpA = a
// TODO 固まることがある
// TOOD 値が微妙に揺れる。。。
if tmpQ == tmpA {
want[0] = want[0] + 1
} else {
want[1] = want[1] + 1
}
case q := <-qCh:
t.Errorf("q %v\n", q)
tmpQ = q
case got := <-rCh:
if want != got {
t.Fatalf("failed got = %v, want = %v", got, want)
}
default:
continue
}
}
})
}
}
Loading