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 translucens #56

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions kadai3/README.md
Original file line number Diff line number Diff line change
@@ -8,6 +8,16 @@
* 標準入力から1行受け取る
* 制限時間内に何問解けたか表示する

遊び方

```sh
./1-typing
```

ゲームのルールを選択する画面が出るので、ターン制か時間制を選ぶ。
Goのキーワードがランダムに出てくるので、タイプして[Enter]
入力との一致度によって得点が加算される。

## 課題3-2

分割ダウンローダーを実装しよう。
@@ -17,3 +27,12 @@
* エラー処理を工夫する
* golang.org/x/sync/errgourpパッケージなどを使ってみる
* キャンセルが発生した場合の実装を行う

使い方
```sh
./2-dler -n 3 -d ./download https://example.com/file
```

`-n`オプションはダウンロード時の分割数。デフォルトは2.
`-d`オプションはダウンロードしたファイルの保存先。デフォルトは`./download`
Ctrl-Cでダウンロードを中断することができる。
9 changes: 9 additions & 0 deletions kadai3/translucens/1-typing/typing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"github.com/translucens/dojo1/kadai3/translucens/1-typing/ui"
)

func main() {
ui.MainScreen()
}
58 changes: 58 additions & 0 deletions kadai3/translucens/1-typing/typinggame/calcscore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package typinggame

// CalcScore caliculates player score based on player input
func CalcScore(correct, playerinput string) int {
editlen := EditLength(correct, playerinput)
correctlen := len(correct)

if editlen > correctlen {
return 0
}

return correctlen - editlen
}

// EditLength caliculates edit distance between two strings
func EditLength(str1, str2 string) int {
len1 := len(str1)
len2 := len(str2)

str1 = " " + str1
str2 = " " + str2

table := make([][]int, len1+1)
for i1 := range table {
table[i1] = make([]int, len2+1)
table[i1][0] = i1
}
for i2 := range table[0] {
table[0][i2] = i2
}

for i1 := range table {
if i1 == 0 {
continue
}

for i2 := range table[i1] {
if i2 == 0 {
continue
}

cost := 0
if str1[i1] != str2[i2] {
cost = 1
}
table[i1][i2] = min(min(table[i1-1][i2]+1, table[i1][i2-1]+1), table[i1-1][i2-1]+cost)
}
}

return table[len1][len2]
}

func min(x, y int) int {
if x < y {
return x
}
return y
}
58 changes: 58 additions & 0 deletions kadai3/translucens/1-typing/typinggame/calcscore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package typinggame

import (
"testing"
)

func TestEditLength(t *testing.T) {
type args struct {
str1 string
str2 string
}
tests := []struct {
name string
args args
want int
}{
{"same", args{"test String", "test String"}, 0},
{"missing one char", args{"test String", "test Strin"}, 1},
{"add one char", args{"test String", "test Stringg"}, 1},
{"empty", args{"test String", ""}, 11},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := EditLength(tt.args.str1, tt.args.str2); got != tt.want {
t.Errorf("EditLength() = %v, want %v", got, tt.want)
}
})
}
}

func TestCalcScore(t *testing.T) {
type args struct {
correct string
userinput string
}
tests := []struct {
name string
args args
want int
}{
{"correct", args{"string", "string"}, 6},
{"small miss", args{"string", "strin"}, 5},
{"small miss2", args{"string", "stringg"}, 5},
{"middle miss", args{"string", "stri"}, 4},
{"middle miss2", args{"string", "string12"}, 4},
{"big miss", args{"string", ""}, 0},
{"big miss2", args{"string", "string1234567"}, 0},
{"short string", args{"go", "go"}, 2},
{"short miss", args{"go", "g"}, 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := CalcScore(tt.args.correct, tt.args.userinput); got != tt.want {
t.Errorf("CalcScore() = %v, want %v", got, tt.want)
}
})
}
}
22 changes: 22 additions & 0 deletions kadai3/translucens/1-typing/typinggame/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package typinggame

import (
"math/rand"
"time"
)

func init() {
rand.Seed(time.Now().Unix())
}

var words = [...]string{"break", "default", "func", "interface", "select",
"case", "defer", "go", "map", "struct",
"chan", "else", "goto", "package", "switch",
"const", "fallthrough", "if", "range", "type",
"continue", "for", "import", "return", "var"}

// RandomWord returns a random chosen word
func RandomWord() string {

return words[rand.Intn(len(words))]
}
179 changes: 179 additions & 0 deletions kadai3/translucens/1-typing/ui/gamescreen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package ui

import (
"bufio"
"fmt"
"io"
"os"
"time"

"github.com/fatih/color"
"github.com/translucens/dojo1/kadai3/translucens/1-typing/typinggame"
)

const (
turncount = 5
warmuptime = 3
timeperchar = 1
timetrialsec = 30
)

var (
yellow = color.New(color.FgYellow).SprintFunc()
red = color.New(color.FgRed).SprintFunc()
blue = color.New(color.FgHiBlue).SprintFunc()
whiteBgcyan = color.New(color.FgHiWhite).Add(color.BgCyan).Add(color.Bold).SprintFunc()
whiteBggreen = color.New(color.FgHiWhite).Add(color.BgGreen).SprintfFunc()
)

// high score and name

// MainScreen is mode selector
func MainScreen() {

fmt.Println(" ______ ______")
fmt.Println(" /_ __/_ ______ ___ / ____/___")
fmt.Println(" / / / / / / __ \\/ _ \\/ / __/ __ \\")
fmt.Println(" / / / /_/ / /_/ / __/ /_/ / /_/ /")
fmt.Println("/_/ \\__, / .___/\\___/\\____/\\____/")
fmt.Println(" /____/_/")

strchan := strinput(os.Stdin)
defer close(strchan)

for {
fmt.Println("Select game mode: ")
fmt.Printf("1: %d turns\n", turncount)
fmt.Printf("2: Timetrial %d sec.\n", timetrialsec)
fmt.Println("Other: Exit")
fmt.Print(whiteBgcyan(">>> "))

command, ok := <-strchan
switch {
case len(command) == 0 || !ok:
return
case command[0] == '1':
printScore(TurnGame(strchan))
case command[0] == '2':
printScore(Timetrial(strchan))
default:
return
}

}

}

// TurnGame shows turn-ruled game screen for player
func TurnGame(strchan <-chan string) (int, int) {

totalscore := 0
totallength := 0

for i := warmuptime; i > 0; i-- {
fmt.Printf("%d...", i)
time.Sleep(time.Second)
}

for i := 1; i <= turncount; i++ {
fmt.Print("Ready...")
time.Sleep(time.Second)

fmt.Printf("Go!!\nTurn %d/%d\n", i, turncount)
word := typinggame.RandomWord()
lenstr, score := SingleTurn(strchan, word, time.Duration(len(word)*timeperchar)*time.Second)

totallength += lenstr
totalscore += score
}
return totallength, totalscore
}

// Timetrial shows time-based game screen
func Timetrial(strchan <-chan string) (int, int) {

totallength, totalscore := 0, 0

for i := warmuptime; i > 0; i-- {
fmt.Printf("%d...", i)
time.Sleep(time.Second)
}
fmt.Print("Ready...")
time.Sleep(time.Second)
fmt.Println("Go!!")

endAt := time.Now().Add(timetrialsec * time.Second)

for endAt.After(time.Now()) {

word := typinggame.RandomWord()

lenstr, score := SingleTurn(strchan, word, endAt.Sub(time.Now()))

totallength += lenstr
totalscore += score
}

return totallength, totalscore
}

func printScore(charcount, score int) {
fmt.Println()
fmt.Println(yellow(" ********************************** "))
fmt.Printf("* Total Score: %d; Accuracy: %.1f%% *\n", score, float64(score)*100.0/float64(charcount))
fmt.Println(yellow(" ********************************** "))
}

// SingleTurn shows typing object and returns word length and score
func SingleTurn(strchan <-chan string, correctstr string, timeout time.Duration) (int, int) {

fmt.Println(whiteBggreen("### %s ### %d [sec.]", correctstr, timeout/time.Second))
fmt.Print(">>> ")

lenstr := len(correctstr)

timer := time.NewTimer(timeout)

for {
select {
case playerstr, ok := <-strchan:

score := 0
if ok {
score = typinggame.CalcScore(correctstr, playerstr)

if score == lenstr {
fmt.Print(yellow("PERFECT! "))
} else {
fmt.Print(red("miss... "))
}

fmt.Printf("Got %d point !\n", score)
}
timer.Stop()

return lenstr, score
case _ = <-timer.C:
fmt.Printf("\nTimeup !!\n")
return lenstr, 0
}
}

}

func strinput(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.Println(err.Error())
}
// EOF
close(ch)
}()

return ch
}
Loading