From 45fb69a6f3533c742556f5ce5f39af0f4cf9d231 Mon Sep 17 00:00:00 2001 From: imura81gt Date: Tue, 24 Sep 2019 19:17:55 +0900 Subject: [PATCH 1/6] add typing game --- kadai3/imura81gt/typ/.devcontainer/Dockerfile | 68 ++++++++++++++++++ .../typ/.devcontainer/devcontainer.json | 32 +++++++++ kadai3/imura81gt/typ/main.go | 7 ++ kadai3/imura81gt/typ/typing/typing.go | 72 +++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 kadai3/imura81gt/typ/.devcontainer/Dockerfile create mode 100644 kadai3/imura81gt/typ/.devcontainer/devcontainer.json create mode 100644 kadai3/imura81gt/typ/main.go create mode 100644 kadai3/imura81gt/typ/typing/typing.go diff --git a/kadai3/imura81gt/typ/.devcontainer/Dockerfile b/kadai3/imura81gt/typ/.devcontainer/Dockerfile new file mode 100644 index 0000000..12623de --- /dev/null +++ b/kadai3/imura81gt/typ/.devcontainer/Dockerfile @@ -0,0 +1,68 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +FROM golang:1 + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +# This Dockerfile adds a non-root 'vscode' user with sudo access. However, for Linux, +# this user's GID/UID must match your local user UID/GID to avoid permission issues +# with bind mounts. Update USER_UID / USER_GID if yours is not 1000. See +# https://aka.ms/vscode-remote/containers/non-root-user for details. +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# Configure apt, install packages and tools +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \ + # + # Verify git, process tools, lsb-release (common in install instructions for CLIs) installed + && apt-get -y install git iproute2 procps lsb-release \ + # + # Install gocode-gomod + && go get -x -d github.com/stamblerre/gocode 2>&1 \ + && go build -o gocode-gomod github.com/stamblerre/gocode \ + && mv gocode-gomod $GOPATH/bin/ \ + # + # Install Go tools + && go get -u -v \ + github.com/mdempsky/gocode \ + github.com/uudashr/gopkgs/cmd/gopkgs \ + github.com/ramya-rao-a/go-outline \ + github.com/acroca/go-symbols \ + github.com/godoctor/godoctor \ + golang.org/x/tools/cmd/guru \ + golang.org/x/tools/cmd/gorename \ + github.com/rogpeppe/godef \ + github.com/zmb3/gogetdoc \ + github.com/haya14busa/goplay/cmd/goplay \ + github.com/sqs/goreturns \ + github.com/josharian/impl \ + github.com/davidrjenni/reftools/cmd/fillstruct \ + github.com/fatih/gomodifytags \ + github.com/cweill/gotests/... \ + golang.org/x/tools/cmd/goimports \ + golang.org/x/lint/golint \ + golang.org/x/tools/cmd/gopls \ + github.com/alecthomas/gometalinter \ + honnef.co/go/tools/... \ + github.com/golangci/golangci-lint/cmd/golangci-lint \ + github.com/mgechev/revive \ + github.com/derekparker/delve/cmd/dlv 2>&1 \ + # + # Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user. + && groupadd --gid $USER_GID $USERNAME \ + && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \ + # [Optional] Add sudo support + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + # + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/kadai3/imura81gt/typ/.devcontainer/devcontainer.json b/kadai3/imura81gt/typ/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e9e5f3e --- /dev/null +++ b/kadai3/imura81gt/typ/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at +// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/go +{ + "name": "Go", + "dockerFile": "Dockerfile", + "runArgs": [ + // Uncomment the next line to use a non-root user. On Linux, this will prevent + // new files getting created as root, but you may need to update the USER_UID + // and USER_GID in .devcontainer/Dockerfile to match your user if not 1000. + // "-u", "vscode", + + "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" + ], + + // Use 'settings' to set *default* container specific settings.json values on container create. + // You can edit these settings after create using File > Preferences > Settings > Remote. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "go.gopath": "/go" + }, + + // Uncomment the next line if you want to publish any ports. + // "appPort": [], + + // Uncomment the next line to run commands after the container is created. + // "postCreateCommand": "go version", + + // Add the IDs of extensions you want installed when the container is created in the array below. + "extensions": [ + "ms-vscode.go" + ] +} \ No newline at end of file diff --git a/kadai3/imura81gt/typ/main.go b/kadai3/imura81gt/typ/main.go new file mode 100644 index 0000000..f31c9ec --- /dev/null +++ b/kadai3/imura81gt/typ/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/gopherdojo/dojo7/kadai3/imura81gt/typ/typing" + +func main() { + typing.Run() +} diff --git a/kadai3/imura81gt/typ/typing/typing.go b/kadai3/imura81gt/typ/typing/typing.go new file mode 100644 index 0000000..9a85b19 --- /dev/null +++ b/kadai3/imura81gt/typ/typing/typing.go @@ -0,0 +1,72 @@ +package typing + +import ( + "bufio" + "fmt" + "io" + "math/rand" + "os" + "time" +) + +func input(r io.Reader) <-chan string { + ch := make(chan string) + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + ch <- s.Text() + } + if err := s.Err(); err != nil { + fmt.Fprintln(os.Stderr, err) + return + } + close(ch) + }() + return ch +} + +func load() string { + var ws = []string{"すもも", "もも"} + rand.Seed(time.Now().UnixNano()) + w1 := ws[rand.Intn(len(ws))] + w2 := ws[rand.Intn(len(ws))] + w3 := ws[rand.Intn(len(ws))] + + return fmt.Sprintf("%sも%sも%sのうち", w1, w2, w3) +} + +// Run is a function to start typing-game. +func Run() { + const ( + limit = 60 + interval = 10 + ) + chi := input(os.Stdin) + + var score int + var chars int + + txt := load() + +B: + for { + fmt.Println(score, chars, ">", txt) + fmt.Print(score, chars, " > ") + select { + case v := <-chi: + if txt == v { + fmt.Println("GOOD!!!") + score++ + chars = chars + len([]rune(txt)) + txt = load() + } else { + fmt.Println("BAD....") + } + case <-time.After(limit * time.Second): + fmt.Println() + fmt.Println("Time up!") + fmt.Println("Score:", score, "points!", chars, "charactors!") + break B + } + } +} From e70784f81edd37f49453ab847aed59d2c69abca1 Mon Sep 17 00:00:00 2001 From: imura81gt Date: Sat, 2 Nov 2019 21:16:19 +0900 Subject: [PATCH 2/6] [typ] fix cancel --- kadai3/imura81gt/README.md | 41 +++++++++++++++++++++++++++ kadai3/imura81gt/typ/typing/typing.go | 20 +++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 kadai3/imura81gt/README.md diff --git a/kadai3/imura81gt/README.md b/kadai3/imura81gt/README.md new file mode 100644 index 0000000..23ee17d --- /dev/null +++ b/kadai3/imura81gt/README.md @@ -0,0 +1,41 @@ +【TRY】タイピングゲームを作ろう +=========================================== + +- [ ] 標準出力に英単語を出す(出すものは自由) +- [x] 標準入力から1行受け取る +- [x] 制限時間内に何問解けたか表示する + + +【TRY】分割ダウンローダを作ろう +=========================================== + +分割ダウンロードを行う + +- [ ]Rangeアクセスを用いる +- [ ]いくつかのゴルーチンでダウンロードしてマージする +- [ ]エラー処理を工夫する +- [ ]golang.org/x/sync/errgourpパッケージなどを使ってみる +- [ ]キャンセルが発生した場合の実装を行う + +ref: https://qiita.com/codehex/items/d0a500ac387d39a34401 + + +Range Request +------------------------------------------------- + +https://developer.mozilla.org/ja/docs/Web/HTTP/Range_requests + +> Accept-Ranges が HTTP レスポンスに存在した場合 (そして値が "none" ではない場合)、サーバーは範囲リクエストに対応しています。これは例えば、 HEAD リクエストを cURL で発行することで確認することができます。 + + +https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept-Ranges + +> Accept-Ranges: bytes +> Accept-Ranges: none + +https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Range + +> Range: =- +> Range: =- +> Range: =-, - +> Range: =-, -, - diff --git a/kadai3/imura81gt/typ/typing/typing.go b/kadai3/imura81gt/typ/typing/typing.go index 9a85b19..f958169 100644 --- a/kadai3/imura81gt/typ/typing/typing.go +++ b/kadai3/imura81gt/typ/typing/typing.go @@ -2,6 +2,7 @@ package typing import ( "bufio" + "context" "fmt" "io" "math/rand" @@ -35,8 +36,18 @@ func load() string { return fmt.Sprintf("%sも%sも%sのうち", w1, w2, w3) } +func show(score int, chars int, txt string) { + fmt.Println(score, chars, ">", txt) + fmt.Print(score, chars, " > ") +} + // Run is a function to start typing-game. func Run() { + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + const ( limit = 60 interval = 10 @@ -48,10 +59,10 @@ func Run() { txt := load() + show(score, chars, txt) + B: for { - fmt.Println(score, chars, ">", txt) - fmt.Print(score, chars, " > ") select { case v := <-chi: if txt == v { @@ -59,13 +70,18 @@ B: score++ chars = chars + len([]rune(txt)) txt = load() + show(score, chars, txt) } else { fmt.Println("BAD....") + show(score, chars, txt) } case <-time.After(limit * time.Second): fmt.Println() fmt.Println("Time up!") fmt.Println("Score:", score, "points!", chars, "charactors!") + cancel() + case <-ctx.Done(): + fmt.Println(ctx.Err()) break B } } From 8b7a9bbc381668d956a6e74fa716b273cff5e041 Mon Sep 17 00:00:00 2001 From: imura81gt Date: Sun, 3 Nov 2019 00:06:46 +0900 Subject: [PATCH 3/6] [typ] refactor and add test for show() --- kadai3/imura81gt/typ/typing/typing.go | 11 +++--- kadai3/imura81gt/typ/typing/typing_test.go | 45 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 kadai3/imura81gt/typ/typing/typing_test.go diff --git a/kadai3/imura81gt/typ/typing/typing.go b/kadai3/imura81gt/typ/typing/typing.go index f958169..e889577 100644 --- a/kadai3/imura81gt/typ/typing/typing.go +++ b/kadai3/imura81gt/typ/typing/typing.go @@ -36,9 +36,8 @@ func load() string { return fmt.Sprintf("%sも%sも%sのうち", w1, w2, w3) } -func show(score int, chars int, txt string) { - fmt.Println(score, chars, ">", txt) - fmt.Print(score, chars, " > ") +func show(score int, chars int, txt string, out io.Writer) { + fmt.Fprintf(out, "%d %d > %s\n%d %d > ", score, chars, txt, score, chars) } // Run is a function to start typing-game. @@ -59,7 +58,7 @@ func Run() { txt := load() - show(score, chars, txt) + show(score, chars, txt, os.Stdout) B: for { @@ -70,10 +69,10 @@ B: score++ chars = chars + len([]rune(txt)) txt = load() - show(score, chars, txt) + show(score, chars, txt, os.Stdout) } else { fmt.Println("BAD....") - show(score, chars, txt) + show(score, chars, txt, os.Stdout) } case <-time.After(limit * time.Second): fmt.Println() diff --git a/kadai3/imura81gt/typ/typing/typing_test.go b/kadai3/imura81gt/typ/typing/typing_test.go new file mode 100644 index 0000000..57693eb --- /dev/null +++ b/kadai3/imura81gt/typ/typing/typing_test.go @@ -0,0 +1,45 @@ +package typing + +import ( + "bytes" + "fmt" + "testing" +) + +func TestInput(t *testing.T) {} + +func TestLoad(t *testing.T) {} + +func TestShow(t *testing.T) { + testcases := []struct { + caseName string + score int + char int + txt string + expected string + }{ + {caseName: "score10char300", score: 10, char: 300, txt: "テスト", expected: "10 300 > テスト\n10 300 > "}, + } + + for _, tc := range testcases { + tc := tc // capture range variable. need to set when run parallel test. + + fmt.Println(tc) + t.Run(tc.caseName, func(t *testing.T) { + t.Parallel() + var buf bytes.Buffer + show(tc.score, tc.char, tc.txt, &buf) + actual := buf.String() + if tc.expected != actual { + t.Errorf("\ncaseName:%s\nactual:%+v\nExpected:%+v\n", + tc.caseName, + actual, + tc.expected, + ) + } + }) + } + +} + +func TestRun(t *testing.T) {} From b43928a6f6cdc0d40a68eafb5605ea2c6fe65a86 Mon Sep 17 00:00:00 2001 From: imura81gt Date: Sun, 3 Nov 2019 00:46:56 +0900 Subject: [PATCH 4/6] [typ] remove Println in TestShow() --- kadai3/imura81gt/typ/typing/typing_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/kadai3/imura81gt/typ/typing/typing_test.go b/kadai3/imura81gt/typ/typing/typing_test.go index 57693eb..80b594d 100644 --- a/kadai3/imura81gt/typ/typing/typing_test.go +++ b/kadai3/imura81gt/typ/typing/typing_test.go @@ -24,7 +24,6 @@ func TestShow(t *testing.T) { for _, tc := range testcases { tc := tc // capture range variable. need to set when run parallel test. - fmt.Println(tc) t.Run(tc.caseName, func(t *testing.T) { t.Parallel() var buf bytes.Buffer From 95e2cc70b100000d3714f5f93b0d6a3ae80e8baa Mon Sep 17 00:00:00 2001 From: imura81gt Date: Sun, 3 Nov 2019 00:47:46 +0900 Subject: [PATCH 5/6] [typ] add TestInput() --- kadai3/imura81gt/typ/typing/typing_test.go | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/kadai3/imura81gt/typ/typing/typing_test.go b/kadai3/imura81gt/typ/typing/typing_test.go index 80b594d..8f76901 100644 --- a/kadai3/imura81gt/typ/typing/typing_test.go +++ b/kadai3/imura81gt/typ/typing/typing_test.go @@ -6,7 +6,37 @@ import ( "testing" ) -func TestInput(t *testing.T) {} +func TestInput(t *testing.T) { + testcases := []struct { + caseName string + input string + expected string + }{ + {caseName: "input some word", input: "foo bar", expected: "foo bar"}, + {caseName: "input line feed", input: "\n", expected: ""}, + } + fmt.Println(testcases) + for _, tc := range testcases { + tc := tc // capture range variable. need to set when run parallel test. + + t.Run(tc.caseName, func(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + buf.Write([]byte(tc.input)) + actual := <-input(&buf) + + if tc.expected != actual { + t.Errorf("\ncaseName:%s\nactual:%+v\nExpected:%+v\n", + tc.caseName, + actual, + tc.expected, + ) + } + }) + } + +} func TestLoad(t *testing.T) {} From 73c537dbd105a0623abd868e24a7ba06bf74ffe9 Mon Sep 17 00:00:00 2001 From: imura81gt Date: Mon, 4 Nov 2019 22:30:45 +0900 Subject: [PATCH 6/6] [type] add testing for load() and add time.Time mock --- kadai3/imura81gt/typ/main.go | 3 +- kadai3/imura81gt/typ/typing/typing.go | 34 ++++++++++++++++++---- kadai3/imura81gt/typ/typing/typing_test.go | 19 +++++++++++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/kadai3/imura81gt/typ/main.go b/kadai3/imura81gt/typ/main.go index f31c9ec..5d22332 100644 --- a/kadai3/imura81gt/typ/main.go +++ b/kadai3/imura81gt/typ/main.go @@ -3,5 +3,6 @@ package main import "github.com/gopherdojo/dojo7/kadai3/imura81gt/typ/typing" func main() { - typing.Run() + g := typing.Game{} + g.Run() } diff --git a/kadai3/imura81gt/typ/typing/typing.go b/kadai3/imura81gt/typ/typing/typing.go index e889577..7992073 100644 --- a/kadai3/imura81gt/typ/typing/typing.go +++ b/kadai3/imura81gt/typ/typing/typing.go @@ -10,6 +10,30 @@ import ( "time" ) +// ----- for time +type Clock interface { + Now() time.Time +} + +type ClockFunc func() time.Time + +func (f ClockFunc) Now() time.Time { + return f() +} + +type Game struct { + Clock Clock +} + +func (g *Game) now() time.Time { + if g.Clock == nil { + return time.Now() + } + return g.Clock.Now() +} + +// ----------- + func input(r io.Reader) <-chan string { ch := make(chan string) go func() { @@ -26,9 +50,9 @@ func input(r io.Reader) <-chan string { return ch } -func load() string { +func (g *Game) load() string { var ws = []string{"すもも", "もも"} - rand.Seed(time.Now().UnixNano()) + rand.Seed(g.now().UnixNano()) w1 := ws[rand.Intn(len(ws))] w2 := ws[rand.Intn(len(ws))] w3 := ws[rand.Intn(len(ws))] @@ -41,7 +65,7 @@ func show(score int, chars int, txt string, out io.Writer) { } // Run is a function to start typing-game. -func Run() { +func (g *Game) Run() { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) @@ -56,7 +80,7 @@ func Run() { var score int var chars int - txt := load() + txt := g.load() show(score, chars, txt, os.Stdout) @@ -68,7 +92,7 @@ B: fmt.Println("GOOD!!!") score++ chars = chars + len([]rune(txt)) - txt = load() + txt = g.load() show(score, chars, txt, os.Stdout) } else { fmt.Println("BAD....") diff --git a/kadai3/imura81gt/typ/typing/typing_test.go b/kadai3/imura81gt/typ/typing/typing_test.go index 8f76901..dc24164 100644 --- a/kadai3/imura81gt/typ/typing/typing_test.go +++ b/kadai3/imura81gt/typ/typing/typing_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "testing" + "time" ) func TestInput(t *testing.T) { @@ -38,7 +39,23 @@ func TestInput(t *testing.T) { } -func TestLoad(t *testing.T) {} +func TestLoad(t *testing.T) { + g := Game{ + Clock: ClockFunc(func() time.Time { + return time.Date(2019, 11, 04, 02, 0, 0, 0, time.UTC) + }), + } + + expected := "すもももももももものうち" + actual := g.load() + if actual != expected { + t.Errorf("\ncaseName:%s\nactual:%+v\nExpected:%+v\n", + "load test", + actual, + expected, + ) + } +} func TestShow(t *testing.T) { testcases := []struct {