diff --git a/kadai3-1/sawadashota/.gitignore b/kadai3-1/sawadashota/.gitignore new file mode 100644 index 0000000..0073616 --- /dev/null +++ b/kadai3-1/sawadashota/.gitignore @@ -0,0 +1,16 @@ +# Created by .ignore support plugin (hsz.mobi) +### Go template +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +vendor/ diff --git a/kadai3-1/sawadashota/Gopkg.lock b/kadai3-1/sawadashota/Gopkg.lock new file mode 100644 index 0000000..b9578f3 --- /dev/null +++ b/kadai3-1/sawadashota/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/corpix/uarand" + packages = ["."] + revision = "2b8494104d86337cdd41d0a49cbed8e4583c0ab4" + +[[projects]] + branch = "master" + name = "github.com/icrowley/fake" + packages = ["."] + revision = "4178557ae428460c3780a381c824a1f3aceb6325" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "d049777ea8addc6ca0ae484aa35573f2d15627addd0a73820193b07608bff3cc" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/kadai3-1/sawadashota/Gopkg.toml b/kadai3-1/sawadashota/Gopkg.toml new file mode 100644 index 0000000..98d8c9c --- /dev/null +++ b/kadai3-1/sawadashota/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + branch = "master" + name = "github.com/icrowley/fake" + +[prune] + go-tests = true + unused-packages = true diff --git a/kadai3-1/sawadashota/README.md b/kadai3-1/sawadashota/README.md new file mode 100644 index 0000000..222d0f8 --- /dev/null +++ b/kadai3-1/sawadashota/README.md @@ -0,0 +1,19 @@ +タイピングゲーム +=== + +表示された英単語をタイピングするゲームです。 + +ゲームの始め方 +--- + +Easy Mode(5文字以内) + +```shell +$ go run main.go +``` + +Hard Mode(6文字以上) + +```shell +$ go run main.go --hard +``` diff --git a/kadai3-1/sawadashota/faker/faker.go b/kadai3-1/sawadashota/faker/faker.go new file mode 100644 index 0000000..02d832c --- /dev/null +++ b/kadai3-1/sawadashota/faker/faker.go @@ -0,0 +1,28 @@ +package faker + +import "github.com/icrowley/fake" + +// ShortWordLength is maximum chars to type easy +const ShortWordLength = 5 + +type Easy struct{} + +// Word returns shorter than 5 chars +func (q *Easy) Word() string { + for { + if w := fake.Word(); len([]rune(w)) <= ShortWordLength { + return w + } + } +} + +type Hard struct{} + +// Word returns shorter than 5 chars +func (q *Hard) Word() string { + for { + if w := fake.Word(); len([]rune(w)) > ShortWordLength { + return w + } + } +} diff --git a/kadai3-1/sawadashota/main.go b/kadai3-1/sawadashota/main.go new file mode 100644 index 0000000..349b33f --- /dev/null +++ b/kadai3-1/sawadashota/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "os" + "time" + + "github.com/gopherdojo/dojo2/kadai3-1/sawadashota/faker" +) + +// AmountTime is amount of game rounds +const AmountTime = 5 + +// Timeout is how long seconds waiting for typing +const Timeout = 5 + +// isHard game mode +var isHard bool + +type Faker interface { + Word() string +} + +func init() { + flag.BoolVar(&isHard, "hard", false, "Hard mode") + flag.Parse() +} + +func main() { + var f Faker + var word string + + if isHard { + fmt.Println("Start Hard Mode!") + f = new(faker.Hard) + } else { + fmt.Println("Start Easy Mode!") + f = new(faker.Easy) + } + + correctCount := 0 + + ch := input(os.Stdin) + + fmt.Println("This is typing game!") + fmt.Printf("Plase type appearing word in %d seconds\n", Timeout) + + for i := 0; i < AmountTime; i++ { + word = f.Word() + + fmt.Printf("\nWord: %s\n", word) + fmt.Print("----> ") + + select { + case <-time.After(Timeout * time.Second): + fmt.Println("Time Over!") + case answer := <-ch: + if word == answer { + fmt.Println("Great!") + correctCount++ + } else { + fmt.Println("Uh-Oh") + } + } + } + + if correctCount == AmountTime { + fmt.Print("\nPerfect!\n") + return + } + + fmt.Printf("Correct: %d, Incorrect: %d\n", correctCount, AmountTime-correctCount) +} + +func input(r io.Reader) <-chan string { + ch := make(chan string) + go func() { + s := bufio.NewScanner(r) + for s.Scan() { + ch <- s.Text() + } + close(ch) + }() + return ch +} diff --git a/kadai3-2/sawadashota/.gitignore b/kadai3-2/sawadashota/.gitignore new file mode 100644 index 0000000..2dd94eb --- /dev/null +++ b/kadai3-2/sawadashota/.gitignore @@ -0,0 +1,2 @@ +v1.0.11.tar.gz +vendor/ diff --git a/kadai3-2/sawadashota/Gopkg.lock b/kadai3-2/sawadashota/Gopkg.lock new file mode 100644 index 0000000..673347e --- /dev/null +++ b/kadai3-2/sawadashota/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = ["context"] + revision = "4cb1c02c05b0e749b0365f61ae859a8e0cfceed9" + +[[projects]] + branch = "master" + name = "golang.org/x/sync" + packages = ["errgroup"] + revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "d0cf11beb356877c13dd3fc4145dd9c60d96b2255923c8dee0372102e4a87782" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/kadai3-2/sawadashota/Gopkg.toml b/kadai3-2/sawadashota/Gopkg.toml new file mode 100644 index 0000000..7220225 --- /dev/null +++ b/kadai3-2/sawadashota/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + branch = "master" + name = "golang.org/x/sync" + +[prune] + go-tests = true + unused-packages = true diff --git a/kadai3-2/sawadashota/README.md b/kadai3-2/sawadashota/README.md new file mode 100644 index 0000000..9e5c411 --- /dev/null +++ b/kadai3-2/sawadashota/README.md @@ -0,0 +1,21 @@ +分割ダウンローダー +=== + +Download +--- + +```bash +$ go run main.go ${URL} +``` + +example + +```bash +$ go run main.go https://github.com/sawadashota/gocmd/archive/v1.0.11.tar.gz +``` + +### Options + +- `-p`: ダウンロードプロセス数(デフォルトはコア数) +- `-t`: タイムアウト(デフォルトは10秒) +- `-o`: 出力先(デフォルトはURLのファイル名) diff --git a/kadai3-2/sawadashota/download/download.go b/kadai3-2/sawadashota/download/download.go new file mode 100644 index 0000000..eb9c51e --- /dev/null +++ b/kadai3-2/sawadashota/download/download.go @@ -0,0 +1,85 @@ +package download + +import ( + "bytes" + "context" + "io" + "net/url" + "os" + "time" +) + +type Downloader struct { + url *url.URL + Option + Data +} + +type Data struct { + filesize uint + data [][]byte +} + +type Option interface { + Proc() int + Timeout() time.Duration + Writer() io.Writer + Output() string +} + +// New Downloader +func New(u *url.URL, opts Option) *Downloader { + return &Downloader{ + url: u, + Option: opts, + Data: Data{}, + } +} + +// URL getter +func (d *Downloader) URL() *url.URL { + return d.url +} + +// Run download +func (d *Downloader) Run() error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + filesize, err := d.FetchFileSize(d.url.String()) + if err != nil { + return err + } + + d.SetFileSize(filesize) + d.data = make([][]byte, d.Proc()) + + eg := d.get(ctx) + if err := eg.Wait(); err != nil { + return err + } + + body := d.Merge() + + f, err := os.Create(d.Output()) + defer f.Close() + + f.Write(body) + + return nil +} + +// SetFileSize is filesize setter +func (d *Data) SetFileSize(size uint) { + d.filesize = size +} + +// Merge data slice +func (d *Data) Merge() []byte { + return bytes.Join(d.data, []byte("")) +} + +// String return merged data +func (d *Data) String() string { + return string(d.Merge()) +} diff --git a/kadai3-2/sawadashota/download/request.go b/kadai3-2/sawadashota/download/request.go new file mode 100644 index 0000000..6c91af9 --- /dev/null +++ b/kadai3-2/sawadashota/download/request.go @@ -0,0 +1,81 @@ +package download + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + + "golang.org/x/sync/errgroup" +) + +type Range struct { + low int + high int + proc int +} + +func NewRange(filesize uint, procs, proc int) *Range { + split := int(filesize) / procs + return &Range{ + low: split * (proc - 1), + high: split * proc, + } +} + +// Low getter +func (r *Range) Low() int { + return r.low +} + +// High getter +func (r *Range) High() int { + return r.high +} + +// FetchFileSize fetch content length and set filesize +func (d *Data) FetchFileSize(URL string) (uint, error) { + resp, err := http.Head(URL) + + if err != nil { + return 0, err + } + + return uint(resp.ContentLength), nil +} + +// Get contents concurrently +func (d *Downloader) get(ctx context.Context) *errgroup.Group { + eg, ctx := errgroup.WithContext(ctx) + + for i := 0; i < d.Proc(); i++ { + i := i + r := NewRange(d.filesize, d.Proc(), i+1) + + eg.Go(func() error { + req, err := http.NewRequest(http.MethodGet, d.URL().String(), nil) + if err != nil { + return err + } + + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", r.Low(), r.High())) + req = req.WithContext(ctx) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + + body, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return err + } + + d.data[i] = body + return nil + }) + } + + return eg +} diff --git a/kadai3-2/sawadashota/main.go b/kadai3-2/sawadashota/main.go new file mode 100644 index 0000000..2d5b437 --- /dev/null +++ b/kadai3-2/sawadashota/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "io" + "log" + "os" + + "fmt" + "time" + + "github.com/gopherdojo/dojo2/kadai3-2/sawadashota/download" + "github.com/gopherdojo/dojo2/kadai3-2/sawadashota/option" +) + +var writer io.Writer + +func init() { + writer = os.Stdout +} + +func main() { + opts, u, err := option.Parse(writer) + + if err != nil { + log.Fatal(err) + } + + d := download.New(u, opts) + start := time.Now() + d.Run() + fmt.Fprintf(d.Writer(), "Duration %f seconds\n", time.Since(start).Seconds()) +} diff --git a/kadai3-2/sawadashota/makefile b/kadai3-2/sawadashota/makefile new file mode 100644 index 0000000..0b2e37f --- /dev/null +++ b/kadai3-2/sawadashota/makefile @@ -0,0 +1,4 @@ +run: + go run main.go https://github.com/sawadashota/gocmd/archive/v1.0.11.tar.gz +unzip-gz: + tar -zxvf v1.0.11.tar.gz diff --git a/kadai3-2/sawadashota/option/option.go b/kadai3-2/sawadashota/option/option.go new file mode 100644 index 0000000..fa0e78a --- /dev/null +++ b/kadai3-2/sawadashota/option/option.go @@ -0,0 +1,70 @@ +package option + +import ( + "flag" + "fmt" + "io" + "net/url" + "path/filepath" + "runtime" + "time" +) + +type Option struct { + proc int + timeout int + output string + writer io.Writer +} + +// DefaultTimeout is default value for request timeout +const DefaultTimeout = 10 + +// Parse CLI options +func Parse(w io.Writer) (*Option, *url.URL, error) { + opts := &Option{ + writer: w, + } + + flag.IntVar(&opts.proc, "p", runtime.NumCPU(), "Parallelism") + flag.IntVar(&opts.timeout, "t", DefaultTimeout, "Timeout") + flag.StringVar(&opts.output, "o", "", "output") + + flag.Parse() + + if len(flag.Args()) < 1 { + return nil, nil, fmt.Errorf("args need url") + } + + u, err := url.Parse(flag.Arg(0)) + + if err != nil { + return nil, nil, err + } + + if opts.output == "" { + opts.output = filepath.Base(u.Path) + } + + return opts, u, nil +} + +// Proc is proc getter +func (o *Option) Proc() int { + return o.proc +} + +// Timeout is timeout getter +func (o *Option) Timeout() time.Duration { + return time.Duration(o.timeout) * time.Second +} + +// Writer +func (o *Option) Writer() io.Writer { + return o.writer +} + +// Output path +func (o *Option) Output() string { + return o.output +}