From 037a48f76007b9836919802f96cbfb51fd50449b Mon Sep 17 00:00:00 2001 From: ramenjuniti Date: Tue, 18 Jun 2019 15:24:24 +0900 Subject: [PATCH 1/2] submit kadai3-1 --- kadai3/ramenjuniti/typinggame/Makefile | 14 ++++ kadai3/ramenjuniti/typinggame/README.md | 32 +++++++++ kadai3/ramenjuniti/typinggame/main.go | 62 ++++++++++++++++ kadai3/ramenjuniti/typinggame/main_test.go | 83 ++++++++++++++++++++++ kadai3/ramenjuniti/typinggame/words.go | 12 ++++ 5 files changed, 203 insertions(+) create mode 100644 kadai3/ramenjuniti/typinggame/Makefile create mode 100644 kadai3/ramenjuniti/typinggame/README.md create mode 100644 kadai3/ramenjuniti/typinggame/main.go create mode 100644 kadai3/ramenjuniti/typinggame/main_test.go create mode 100644 kadai3/ramenjuniti/typinggame/words.go diff --git a/kadai3/ramenjuniti/typinggame/Makefile b/kadai3/ramenjuniti/typinggame/Makefile new file mode 100644 index 0000000..13ae418 --- /dev/null +++ b/kadai3/ramenjuniti/typinggame/Makefile @@ -0,0 +1,14 @@ +BIN := typinggame + +.PHONY: test +test: + go test -cover -v ./... + +.PHONY: build +build: test + go build -o $(BIN) + +.PHONY: clean +clean: + rm $(BIN) + go clean \ No newline at end of file diff --git a/kadai3/ramenjuniti/typinggame/README.md b/kadai3/ramenjuniti/typinggame/README.md new file mode 100644 index 0000000..9ed4547 --- /dev/null +++ b/kadai3/ramenjuniti/typinggame/README.md @@ -0,0 +1,32 @@ +# Typing Game + +## Description + +タイピングゲームです。 + +一行ずつ判定します。 + +`Score` は、どれぐらい出題単語を正しくタイプできているかどうかで加算されます。 + +例えば、`abcdef`と出題された時に`abcd`とタイプした場合、Score は 4 ポイント加算されます。 + +`type/sec`は、1 秒間に正しく入力したタイプ数です。 + +## Usage + +```bash +make build +./typinggame -t {制限時間} +``` + +## Build + +```bash +make build +``` + +## Test + +```bash +make test +``` diff --git a/kadai3/ramenjuniti/typinggame/main.go b/kadai3/ramenjuniti/typinggame/main.go new file mode 100644 index 0000000..c9185b3 --- /dev/null +++ b/kadai3/ramenjuniti/typinggame/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "math/rand" + "os" + "time" +) + +func main() { + t := flag.Int("t", 10, "制限時間(秒)") + flag.Parse() + + var score int + l := time.After(time.Duration(*t) * time.Second) + in := input(os.Stdin) + + rand.Seed(time.Now().UnixNano()) + + fmt.Println("Start!!") +L: + for { + q := words[rand.Intn(len(words))] + fmt.Println(q) + fmt.Print(">> ") + select { + case a := <-in: + score += judge(q, a) + case <-l: + fmt.Println("finish!!") + break L + } + } + fmt.Printf("Score: %v, type/sec: %2.1f\n", score, float64(score)/float64(*t)) +} + +func judge(q, a string) int { + var score int + for i := 0; i < len(q); i++ { + if i == len(a) { + break + } + if q[i] == a[i] { + score++ + } + } + return score +} + +func input(r io.Reader) <-chan string { + c := make(chan string) + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + c <- s.Text() + } + }() + return c +} diff --git a/kadai3/ramenjuniti/typinggame/main_test.go b/kadai3/ramenjuniti/typinggame/main_test.go new file mode 100644 index 0000000..823fc2b --- /dev/null +++ b/kadai3/ramenjuniti/typinggame/main_test.go @@ -0,0 +1,83 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestJudge(t *testing.T) { + tests := []struct { + name string + q string + a string + score int + }{ + { + name: "case1", + q: "abc", + a: "abc", + score: 3, + }, + { + name: "case2", + q: "abc", + a: "ab", + score: 2, + }, + { + name: "case3", + q: "ab", + a: "abc", + score: 2, + }, + { + name: "case4", + q: "", + a: "abc", + score: 0, + }, + { + name: "case5", + q: "abc", + a: "", + score: 0, + }, + { + name: "case6", + q: "", + a: "", + score: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := judge(test.q, test.a); got != test.score { + t.Errorf("got %v, want %v", got, test.score) + } + }) + } +} + +func TestInput(t *testing.T) { + tests := []struct { + name string + in string + out string + }{ + { + name: "case1", + in: "abc", + out: "abc", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + r := bytes.NewBuffer([]byte(test.in)) + if got := <-input(r); got != test.out { + t.Errorf("got %v, want %v", got, test.out) + } + }) + } +} diff --git a/kadai3/ramenjuniti/typinggame/words.go b/kadai3/ramenjuniti/typinggame/words.go new file mode 100644 index 0000000..703b485 --- /dev/null +++ b/kadai3/ramenjuniti/typinggame/words.go @@ -0,0 +1,12 @@ +package main + +var words = []string{ + "ra-men", + "jirou", + "yasai", + "ninnniku", + "abura", + "karame", + "mashi", + "mashimashi", +} From 44ba77bada6386fadf6211ef8730cda81da81175 Mon Sep 17 00:00:00 2001 From: ramenjuniti Date: Fri, 21 Jun 2019 02:10:07 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E5=88=86=E5=89=B2=E3=83=80=E3=82=A6?= =?UTF-8?q?=E3=83=B3=E3=83=AD=E3=83=BC=E3=83=80=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{typinggame => gdown}/Makefile | 4 +- kadai3/ramenjuniti/gdown/README.md | 19 ++ kadai3/ramenjuniti/gdown/cmd/gdown/main.go | 37 ++++ kadai3/ramenjuniti/gdown/gdown.go | 173 ++++++++++++++++++ kadai3/ramenjuniti/gdown/go.mod | 5 + kadai3/ramenjuniti/gdown/go.sum | 2 + kadai3/ramenjuniti/typinggame/README.md | 32 ---- kadai3/ramenjuniti/typinggame/main.go | 62 ------- kadai3/ramenjuniti/typinggame/main_test.go | 83 --------- kadai3/ramenjuniti/typinggame/words.go | 12 -- 10 files changed, 238 insertions(+), 191 deletions(-) rename kadai3/ramenjuniti/{typinggame => gdown}/Makefile (71%) create mode 100644 kadai3/ramenjuniti/gdown/README.md create mode 100644 kadai3/ramenjuniti/gdown/cmd/gdown/main.go create mode 100644 kadai3/ramenjuniti/gdown/gdown.go create mode 100644 kadai3/ramenjuniti/gdown/go.mod create mode 100644 kadai3/ramenjuniti/gdown/go.sum delete mode 100644 kadai3/ramenjuniti/typinggame/README.md delete mode 100644 kadai3/ramenjuniti/typinggame/main.go delete mode 100644 kadai3/ramenjuniti/typinggame/main_test.go delete mode 100644 kadai3/ramenjuniti/typinggame/words.go diff --git a/kadai3/ramenjuniti/typinggame/Makefile b/kadai3/ramenjuniti/gdown/Makefile similarity index 71% rename from kadai3/ramenjuniti/typinggame/Makefile rename to kadai3/ramenjuniti/gdown/Makefile index 13ae418..adc6bde 100644 --- a/kadai3/ramenjuniti/typinggame/Makefile +++ b/kadai3/ramenjuniti/gdown/Makefile @@ -1,4 +1,4 @@ -BIN := typinggame +BIN := gdown .PHONY: test test: @@ -6,7 +6,7 @@ test: .PHONY: build build: test - go build -o $(BIN) + go build -o $(BIN) ./cmd/gdown .PHONY: clean clean: diff --git a/kadai3/ramenjuniti/gdown/README.md b/kadai3/ramenjuniti/gdown/README.md new file mode 100644 index 0000000..e1e313f --- /dev/null +++ b/kadai3/ramenjuniti/gdown/README.md @@ -0,0 +1,19 @@ +# gdown + +## Usage + +```bash +./gdown -p {並列数} {URL} +``` + +## Build + +```bash +make build +``` + +## Test + +```bash +make test +``` diff --git a/kadai3/ramenjuniti/gdown/cmd/gdown/main.go b/kadai3/ramenjuniti/gdown/cmd/gdown/main.go new file mode 100644 index 0000000..35dd871 --- /dev/null +++ b/kadai3/ramenjuniti/gdown/cmd/gdown/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "flag" + "fmt" + "os" + "runtime" + + "github.com/gopherdojo/dojo5/kadai3/ramenjuniti/gdown" +) + +func main() { + p := flag.Int("p", runtime.NumCPU(), "並列数") + flag.Parse() + + if *p < 1 { + fmt.Fprintln(os.Stderr, "p cannot be less than 1") + os.Exit(1) + } + + url := flag.Arg(0) + if url == "" { + fmt.Fprintln(os.Stderr, "please input URL") + os.Exit(1) + } + + c, err := gdown.New(url, *p) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if err = c.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/kadai3/ramenjuniti/gdown/gdown.go b/kadai3/ramenjuniti/gdown/gdown.go new file mode 100644 index 0000000..19d88b7 --- /dev/null +++ b/kadai3/ramenjuniti/gdown/gdown.go @@ -0,0 +1,173 @@ +package gdown + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strings" + + "golang.org/x/sync/errgroup" +) + +type RangeRequest struct { + URL string + FileName string + Unit int64 + Ranges []*Range +} + +type Range struct { + start int64 + end int64 +} + +func New(rawurl string, p int) (*RangeRequest, error) { + u, err := url.Parse(rawurl) + if err != nil { + return nil, err + } + + fn := getName(u.Path) + + res, err := http.Head(rawurl) + if err != nil { + return nil, err + } + defer res.Body.Close() + + if res.Header.Get("Accept-Ranges") != "bytes" { + return &RangeRequest{URL: rawurl, FileName: fn, Ranges: nil}, nil + } + + cl := res.ContentLength + unit := cl / int64(p) + ranges := make([]*Range, p) + + for i := 0; i < p; i++ { + start := int64(i) * unit + end := start + unit - 1 + if i == p-1 { + end = cl + } + + ranges[i] = &Range{start: start, end: end} + } + + return &RangeRequest{URL: rawurl, FileName: fn, Unit: unit, Ranges: ranges}, nil +} + +func (r *RangeRequest) Run() error { + if r.Ranges == nil { + req, err := http.NewRequest(http.MethodGet, r.URL, nil) + if err != nil { + return err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + return save(r.FileName, res) + + } else { + g, ctx := errgroup.WithContext(context.Background()) + + for i, ran := range r.Ranges { + i, ran := i, ran + tmpn := fmt.Sprintf("%s-%d", r.FileName, i) + + if info, err := os.Stat(tmpn); err == nil { + size := info.Size() + if i == len(r.Ranges)-1 { + if size == ran.end-ran.start { + continue + } + } else if size == r.Unit { + continue + } + ran.start += size + } + + g.Go(func() error { + req, err := makeRangeReqest(ctx, r.URL, ran.start, ran.end) + if err != nil { + return err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + return save(tmpn, res) + }) + } + + if err := g.Wait(); err != nil { + return err + } + + return merge(r.FileName, len(r.Ranges)) + } +} + +func makeRangeReqest(ctx context.Context, url string, start, end int64) (*http.Request, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end)) + + return req, nil +} + +func getName(url string) string { + us := strings.Split(url, "/") + return us[len(us)-1] +} + +func save(fn string, res *http.Response) error { + f, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.Copy(f, res.Body); err != nil { + return err + } + + return nil +} + +func merge(fn string, p int) error { + f, err := os.Create(fn) + if err != nil { + return err + } + defer f.Close() + + for i := 0; i < p; i++ { + tmpn := fmt.Sprintf("%s-%d", fn, i) + tmp, err := os.Open(tmpn) + if err != nil { + return err + } + + io.Copy(f, tmp) + tmp.Close() + + if err := os.Remove(tmpn); err != nil { + return err + } + } + + return nil +} diff --git a/kadai3/ramenjuniti/gdown/go.mod b/kadai3/ramenjuniti/gdown/go.mod new file mode 100644 index 0000000..0384cf8 --- /dev/null +++ b/kadai3/ramenjuniti/gdown/go.mod @@ -0,0 +1,5 @@ +module github.com/gopherdojo/dojo5/kadai3/ramenjuniti/gdown + +go 1.12 + +require golang.org/x/sync v0.0.0-20190423024810-112230192c58 diff --git a/kadai3/ramenjuniti/gdown/go.sum b/kadai3/ramenjuniti/gdown/go.sum new file mode 100644 index 0000000..6eae930 --- /dev/null +++ b/kadai3/ramenjuniti/gdown/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/kadai3/ramenjuniti/typinggame/README.md b/kadai3/ramenjuniti/typinggame/README.md deleted file mode 100644 index 9ed4547..0000000 --- a/kadai3/ramenjuniti/typinggame/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Typing Game - -## Description - -タイピングゲームです。 - -一行ずつ判定します。 - -`Score` は、どれぐらい出題単語を正しくタイプできているかどうかで加算されます。 - -例えば、`abcdef`と出題された時に`abcd`とタイプした場合、Score は 4 ポイント加算されます。 - -`type/sec`は、1 秒間に正しく入力したタイプ数です。 - -## Usage - -```bash -make build -./typinggame -t {制限時間} -``` - -## Build - -```bash -make build -``` - -## Test - -```bash -make test -``` diff --git a/kadai3/ramenjuniti/typinggame/main.go b/kadai3/ramenjuniti/typinggame/main.go deleted file mode 100644 index c9185b3..0000000 --- a/kadai3/ramenjuniti/typinggame/main.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "bufio" - "flag" - "fmt" - "io" - "math/rand" - "os" - "time" -) - -func main() { - t := flag.Int("t", 10, "制限時間(秒)") - flag.Parse() - - var score int - l := time.After(time.Duration(*t) * time.Second) - in := input(os.Stdin) - - rand.Seed(time.Now().UnixNano()) - - fmt.Println("Start!!") -L: - for { - q := words[rand.Intn(len(words))] - fmt.Println(q) - fmt.Print(">> ") - select { - case a := <-in: - score += judge(q, a) - case <-l: - fmt.Println("finish!!") - break L - } - } - fmt.Printf("Score: %v, type/sec: %2.1f\n", score, float64(score)/float64(*t)) -} - -func judge(q, a string) int { - var score int - for i := 0; i < len(q); i++ { - if i == len(a) { - break - } - if q[i] == a[i] { - score++ - } - } - return score -} - -func input(r io.Reader) <-chan string { - c := make(chan string) - go func() { - s := bufio.NewScanner(r) - for s.Scan() { - c <- s.Text() - } - }() - return c -} diff --git a/kadai3/ramenjuniti/typinggame/main_test.go b/kadai3/ramenjuniti/typinggame/main_test.go deleted file mode 100644 index 823fc2b..0000000 --- a/kadai3/ramenjuniti/typinggame/main_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestJudge(t *testing.T) { - tests := []struct { - name string - q string - a string - score int - }{ - { - name: "case1", - q: "abc", - a: "abc", - score: 3, - }, - { - name: "case2", - q: "abc", - a: "ab", - score: 2, - }, - { - name: "case3", - q: "ab", - a: "abc", - score: 2, - }, - { - name: "case4", - q: "", - a: "abc", - score: 0, - }, - { - name: "case5", - q: "abc", - a: "", - score: 0, - }, - { - name: "case6", - q: "", - a: "", - score: 0, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := judge(test.q, test.a); got != test.score { - t.Errorf("got %v, want %v", got, test.score) - } - }) - } -} - -func TestInput(t *testing.T) { - tests := []struct { - name string - in string - out string - }{ - { - name: "case1", - in: "abc", - out: "abc", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - r := bytes.NewBuffer([]byte(test.in)) - if got := <-input(r); got != test.out { - t.Errorf("got %v, want %v", got, test.out) - } - }) - } -} diff --git a/kadai3/ramenjuniti/typinggame/words.go b/kadai3/ramenjuniti/typinggame/words.go deleted file mode 100644 index 703b485..0000000 --- a/kadai3/ramenjuniti/typinggame/words.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -var words = []string{ - "ra-men", - "jirou", - "yasai", - "ninnniku", - "abura", - "karame", - "mashi", - "mashimashi", -}