-
Notifications
You must be signed in to change notification settings - Fork 7
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build/ |
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 |
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{ | ||
TimeUpSecond: timeout, | ||
IsColor: color, | ||
}, os.Stdin, os.Stdout, os.Stderr) | ||
|
||
if err != nil { | ||
log.Fatal("Failed to start the game") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
} |
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) | ||
} |
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 | ||
} |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. プログラムの外部に出る情報には |
||
ExitError | ||
) | ||
|
||
// Game is manages game information | ||
type Game struct { | ||
qs *questions.Questions | ||
*Result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
IsColor bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
// DefaultOptions is the default value of Options. | ||
var DefaultOptions = Options{ | ||
TimeUpSecond: 30, | ||
IsColor: false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
// 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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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{}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 呼び出しの度にSeedをセットしない |
||
index := rand.Intn(g.qs.GetSize()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
基本ポインタにしておく。