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

Kadai3-1: nagaa052 #25

Open
wants to merge 4 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
1 change: 1 addition & 0 deletions kadai3-1/nagaa052/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
29 changes: 29 additions & 0 deletions kadai3-1/nagaa052/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
NAME := tgame

GO ?= go
BUILD_DIR=./build
BINARY ?= $(BUILD_DIR)/$(NAME)

.PHONY: all
all: clean test build

.PHONY: test
test:
$(GO) test -v -race ./...

.PHONY: test_integration
test_integration:
$(GO) test -v -tags=integration ./...

.PHONY: test_cover
test_cover:
$(GO) test -v -cover ./...

.PHONY: clean
clean:
$(GO) clean
rm -f $(BINARY)

.PHONY: build
build:
$(GO) build -o $(BINARY) -v
40 changes: 40 additions & 0 deletions kadai3-1/nagaa052/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"flag"
"fmt"
"log"
"os"

"github.com/gopherdojo/dojo5/kadai3-1/nagaa052/pkg/game"
)

func main() {
var timeout int
var color bool
flag.IntVar(&timeout, "t", game.DefaultOptions.TimeUpSecond, "Timeout Seconds")
flag.BoolVar(&color, "c", game.DefaultOptions.IsColor, "Print Color")
flag.Usage = usage
flag.Parse()

g, err := game.New(game.Options{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

基本ポインタにしておく。

TimeUpSecond: timeout,
IsColor: color,
}, os.Stdin, os.Stdout, os.Stderr)

if err != nil {
log.Fatal("Failed to start the game")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log.Fatalは使わない

}

os.Exit(g.Start())
}

func usage() {
fmt.Fprintf(os.Stderr, `
tgame is a Typing Game
Usage:
tgame [option]
Options:
`)
flag.PrintDefaults()
}
19 changes: 19 additions & 0 deletions kadai3-1/nagaa052/pkg/game/color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package game

import (
"fmt"
"io"
)

type colorCode int

const (
red colorCode = 31
green colorCode = 32
yellow colorCode = 33
blue colorCode = 34
)

func cFPrint(code colorCode, w io.Writer, text string) {
fmt.Fprintf(w, "\x1b[%dm%s\x1b[0m\n", code, text)
}
11 changes: 11 additions & 0 deletions kadai3-1/nagaa052/pkg/game/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package game

import (
"github.com/gopherdojo/dojo5/kadai3-1/nagaa052/pkg/questions"
)

var ExportGetQuestion = (*Game).getQuestion

func (g *Game) ExportSetQs(qs *questions.Questions) {
g.qs = qs
}
174 changes: 174 additions & 0 deletions kadai3-1/nagaa052/pkg/game/game.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
Typing game main logic
*/
package game

import (
"bufio"
"context"
"fmt"
"io"
"math/rand"
"time"

"github.com/gopherdojo/dojo5/kadai3-1/nagaa052/pkg/questions"
)

const (
ExitOK = iota
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

プログラムの外部に出る情報にはiotaを使わない。
例:DBに保存されるもの、ネットワークを介して送られるもの、コマンドライツールの出力になるもの

ExitError
)

// Game is manages game information
type Game struct {
qs *questions.Questions
*Result
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

埋め込む必要性は?

Options
inStream io.Reader
outStream, errStream io.Writer
}

// Options is a specifiable option.
type Options struct {
TimeUpSecond int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

time.Durationを使う

IsColor bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is?

}

// DefaultOptions is the default value of Options.
var DefaultOptions = Options{
TimeUpSecond: 30,
IsColor: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

falseなら別に初期化する必要ないのでは?

}

// Result is manages result information.
type Result struct {
Questions []*questions.Question
CorrectCount int
}

// Print is Output the result.
func (r *Result) Print(out io.Writer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

io.Writerの変数はwと書くことが多い

cr := float64(r.CorrectCount) / float64(len(r.Questions)) * 100
fmt.Fprintln(out, "========================")
fmt.Fprintf(out, "Correct Count: %d\n", r.CorrectCount)
fmt.Fprintf(out, "Correct Rate: %.1f%\n", cr)
}

// New is Generate a new game.
func New(opt Options, inStream io.Reader, outStream, errStream io.Writer) (*Game, error) {
if opt.TimeUpSecond <= 0 {
opt.TimeUpSecond = DefaultOptions.TimeUpSecond
}

qs, err := questions.New()
if err != nil {
return nil, err
}

return &Game{
qs: qs,
Result: &Result{},
Copy link
Member

@tenntenn tenntenn Jun 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

埋め込むならポインタじゃなくてもいい。そしたらゼロ値で使える。

Options: opt,
inStream: inStream,
outStream: outStream,
errStream: errStream,
}, nil
}

// Start is Start Game
func (g *Game) Start() int {
g.printStart()

bc := context.Background()
ctx, cannel := context.WithTimeout(bc, time.Duration(g.TimeUpSecond)*time.Second)
defer cannel()

dst := g.startScanner()

return func() int {
for {
q, err := g.getQuestion()
if err != nil {
fmt.Fprintf(g.errStream, "%v\n", err.Error())
return ExitError
}
g.printQuestion(q.Word)

select {
case <-ctx.Done():
g.printTimeOut()
return ExitOK
case input := <-dst:
if q.IsCorrect(input) {
g.Result.CorrectCount++
}
}
}
}()
}

func (g *Game) startScanner() <-chan string {

dst := make(chan string)

go func() {
scanner := bufio.NewScanner(g.inStream)
defer close(dst)

for scanner.Scan() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

エラー処理

dst <- scanner.Text()
}
}()

return dst
}

func (g *Game) getQuestion() (*questions.Question, error) {

rand.Seed(time.Now().UnixNano())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

呼び出しの度にSeedをセットしない

index := rand.Intn(g.qs.GetSize())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同じ問題が出る


q, err := g.qs.GetOne(index)
if err != nil {
return nil, err
}

g.Result.Questions = append(g.Result.Questions, q)
return q, nil
}

func (g *Game) printStart() {
for i := 3; i > 0; i-- {
fmt.Fprintf(g.outStream, "%d", i)
time.Sleep(250 * time.Millisecond)

fmt.Fprint(g.outStream, ".")
time.Sleep(250 * time.Millisecond)
fmt.Fprint(g.outStream, ".")
time.Sleep(250 * time.Millisecond)
fmt.Fprint(g.outStream, ".")
time.Sleep(250 * time.Millisecond)
}
fmt.Fprintln(g.outStream, "Start!!")
fmt.Fprintln(g.outStream, "========================")
time.Sleep(500 * time.Millisecond)
}

func (g *Game) printQuestion(word string) {
if g.IsColor {
cFPrint(green, g.outStream, fmt.Sprintf("%s", word))
} else {
fmt.Fprintf(g.outStream, "%s", word)
}
}

func (g *Game) printTimeOut() {
if g.IsColor {
cFPrint(red, g.outStream, "\nTimeUp!!!")
} else {
fmt.Fprintf(g.outStream, "\nTimeUp!!!")
}

time.Sleep(1 * time.Second)
g.Result.Print(g.outStream)
}
Loading