はじめに
Goの学び直しとして、最近はメルカリさんの「プログラミング言語Go完全入門」に沿って学習していて、そちらのお題であったタイピングゲーム(ターミナル上で遊べる)を作成してみました。
Demo
ソース
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"time"
"github.com/tjarratt/babble"
)
func main() {
var (
ch_rcv = myInput(os.Stdin)
t = 1 // タイムリミット
tl = time.After(time.Duration(t) * time.Minute) // 制限時間処理
n = 0
)
// Babbleという、英文字をランダム生成してくれるライブラリを使用(英単語ではない)
babbler := babble.NewBabbler()
babbler.Count = 1
fmt.Println("Start the typing game." + " Time limit is " + strconv.Itoa(t) + " second." + " Yay, start!")
OuterLoop:
for {
// 英文字をランダムに生成し出力
q := babbler.Babble()
fmt.Println(q)
select {
case <-tl: // 制限時間が来た時の処理
fmt.Println("Finished!" + " Your score is " + strconv.Itoa(n) + " points! Good job:)")
break OuterLoop
case x := <-ch_rcv: // お題と入力した値の比較処理
if x == q {
fmt.Println("OK!")
n += 1
} else {
fmt.Println("NG :(")
}
}
}
}
/*
標準入力をforの無限ループで受付け、
戻り値を受信専用のチャネル型に(最終的にselectで受信caseとして扱うため)
*/
func myInput(r io.Reader) <-chan string {
ch := make(chan string)
go func() {
s := bufio.NewScanner(r)
for s.Scan() {
ch <- s.Text()
}
}()
return ch
}
工夫・苦戦した点
お題の生成方法
どのようにして英単語を自動生成すれば良いか検討がつかなかったが、ググっていくと、Babbleという英文字をランダムに生成してくれるライブラリがあったので、そちらを使うことに。Usageも詳しく記載あったので、そこからは早かったです。
標準入力の受付け
もちろん入力を一度のみしか受付けないタイピングゲームは見たことがないので、入力があった場合は無限に受け付けるようにしないといけないですね。
そこでforを使い、Scan()
して、入力が検知される限り、チャネル送信し、selectにて受付けるようにしました。
time.After引数に直接変数を代入すると・・・
time.After(xx * time.Minute)
のxxの部分に、intを代入した変数を直接ぶっ込むと、下記エラーが出現。
invalid operation: second * time.Second (mismatched types int and time.Duration)
結論、こちらを参考にさせていただき解消。引用させていただくと、下記の通りでした。
time.After()ではtime.Duration型を受け付けますが, int型*Duration型は使えないみたいです。
そのため, 時刻処理にint型を使用する際にはtime.Duration()でラップしてやる必要があります。
最後に
メルカリさんの「プログラミング言語Go完全入門」は本当にわかりやすく、各章の解説動画もあるので、大変ありがたいです。
今回はゴールーチン、チャネル、selectを中心に理解を深めていきましたが、contextの方が未だあやしいので、次はそちらを学習しながら、最終的にはフロントが少しだけリッチなアプリを作成できたらいいなと考えております。
最後までご拝読いただき、有難うございました。
※まだまだ未熟なので、お気づきの点ございましたらコメント頂けますと幸いです。