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 by Onoyama #40

Open
wants to merge 1 commit 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
51 changes: 51 additions & 0 deletions kadai3/onoyama/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 解説 (Gopher道場 課題 3-1)

## コマンド
./Questions
(上記コマンドを実行後、画面の指示に従ってください)

## ライブラリ

### PACKAGE DOCUMENTATION

package utils
import "./utils"

### FUNCTIONS

func CheckAnswer(question Question, answer string) bool
 回答があっているか確認して結果を表示

func InputChannel(r io.Reader) <-chan string
 入力用のチャネル

func LoadQuestions(path string) []Question
 JSONファイルから問題をロード

func ShowResult(result Result)
 正解の合計を表示

func TimeoutChannel(timeout int) <-chan bool
 タイムアウト用のチャネル

### TYPES

type Question struct {
  Question string ``json:"question"``
  Answer string ``json:"answer"``
}
 質問格納用struct

func GetQuestion(questions []Question) Question
 問題の配列からランダムに一問抽出

func PopQuestion(questions []Question, q_count int) Question
 問題の表示

type Result struct {
  Count int
  Correct int
}
 回答結果の格納用struct


5 changes: 5 additions & 0 deletions kadai3/onoyama/json/questions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{"question": "test1", "answer": "テスト1"},
{"question": "test2", "answer": "テスト2"},
{"question": "test3", "answer": "テスト3"}
]
1 change: 1 addition & 0 deletions kadai3/onoyama/json/words.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"question": "ability", "answer": "能力"}, {"question": "able", "answer": "することができる"}, {"question": "about", "answer": "について"}, {"question": "above", "answer": "の上に"}, {"question": "absolute", "answer": "絶対的な"}, {"question": "absolutely", "answer": "完全に"}, {"question": "accept", "answer": "受け入れる"}, {"question": "acceptable", "answer": "許容できる"}, {"question": "account", "answer": "口座"}, {"question": "across", "answer": "横切って"}, {"question": "act", "answer": "行動する"}, {"question": "action", "answer": "行動"}, {"question": "actual", "answer": "実際の"}, {"question": "actually", "answer": "実際は"}, {"question": "add", "answer": "加える"}, {"question": "addition", "answer": "追加"}, {"question": "additional", "answer": "追加の"}, {"question": "address", "answer": "住所"}, {"question": "admit", "answer": "認める"}, {"question": "advertise", "answer": "宣伝する"}, {"question": "advertisement", "answer": "広告"}, {"question": "afford", "answer": "する余裕がある"}, {"question": "afraid", "answer": "怖がって"}, {"question": "after", "answer": "後で"}, {"question": "afternoon", "answer": "午後"}, {"question": "again", "answer": "再び"}, {"question": "against", "answer": "に反対して"}, {"question": "age", "answer": "年齢"}, {"question": "ago", "answer": "前に"}, {"question": "agree", "answer": "同意する"}, {"question": "agreement", "answer": "合意"}, {"question": "ahead", "answer": "前方に"}, {"question": "air", "answer": "空気"}, {"question": "all", "answer": "すべて"}, {"question": "allow", "answer": "許可する"}, {"question": "almost", "answer": "ほとんど"}, {"question": "alone", "answer": "独りで"}, {"question": "along", "answer": "に沿って"}, {"question": "already", "answer": "すでに"}, {"question": "alright", "answer": "申し分ない"}, {"question": "also", "answer": "もまた"}, {"question": "although", "answer": "だけれども"}, {"question": "always", "answer": "いつも"}, {"question": "amaze", "answer": "びっくりさせる"}, {"question": "among", "answer": "の間に"}, {"question": "amount", "answer": "量"}, {"question": "and", "answer": "と"}, {"question": "angry", "answer": "腹を立てている"}, {"question": "animal", "answer": "動物"}, {"question": "another", "answer": "もう一つの"}, {"question": "answer", "answer": "答え"}, {"question": "any", "answer": "何か"}, {"question": "anybody", "answer": "誰か"}, {"question": "anymore", "answer": "もはやこれ以上しない"}, {"question": "anyone", "answer": "誰か"}, {"question": "anything", "answer": "何か"}, {"question": "anyway", "answer": "とにかく"}, {"question": "anywhere", "answer": "どこかへ"}, {"question": "apart", "answer": "離れて"}, {"question": "apparent", "answer": "明白な"}, {"question": "apparently", "answer": "明白に"}, {"question": "appear", "answer": "現れる"}, {"question": "appearance", "answer": "外観"}, {"question": "area", "answer": "地域;場所"}, {"question": "arm", "answer": "腕"}, {"question": "around", "answer": "の周りに"}, {"question": "arrival", "answer": "到着"}, {"question": "arrive", "answer": "到着する"}, {"question": "art", "answer": "芸術"}, {"question": "artist", "answer": "芸術家"}, {"question": "as", "answer": "同じぐらい"}, {"question": "ashamed", "answer": "恥じている"}, {"question": "ask", "answer": "尋ねる"}, {"question": "at", "answer": "の所で"}, {"question": "autumn", "answer": "秋"}, {"question": "aware", "answer": "気づいている"}, {"question": "awareness", "answer": "認識"}, {"question": "away", "answer": "離れて"}, {"question": "awful", "answer": "恐ろしい"}, {"question": "baby", "answer": "赤ん坊"}, {"question": "back", "answer": "もとに戻って"}, {"question": "bad", "answer": "悪い"}, {"question": "badly", "answer": "悪く"}, {"question": "bag", "answer": "かばん"}, {"question": "ball", "answer": "ボール"}, {"question": "bank", "answer": "銀行"}, {"question": "bar", "answer": "妨げる"}, {"question": "basic", "answer": "基本的な"}, {"question": "basically", "answer": "基本的には"}, {"question": "bath", "answer": "浴槽"}, {"question": "be", "answer": "である"}, {"question": "beach", "answer": "砂浜"}, {"question": "bear", "answer": "熊"}, {"question": "beat", "answer": "打ち負かす"}, {"question": "beautiful", "answer": "美しい"}, {"question": "beauty", "answer": "美人"}, {"question": "because", "answer": "だから"}, {"question": "become", "answer": "になる"}, {"question": "bed", "answer": "ベッド"}, {"question": "before", "answer": "以前に"}, {"question": "begin", "answer": "始まる"}, {"question": "behind", "answer": "の後ろに"}, {"question": "believe", "answer": "信じる"}, {"question": "below", "answer": "下に"}, {"question": "beneath", "answer": "の下に"}, {"question": "beside", "answer": "の近くに"}, {"question": "besides", "answer": "のほか"}, {"question": "bet", "answer": "賭ける"}, {"question": "between", "answer": "の間に"}, {"question": "beyond", "answer": "の向こうに"}, {"question": "big", "answer": "大きい"}, {"question": "bill", "answer": "請求書"}, {"question": "billion", "answer": "十億"}, {"question": "bird", "answer": "鳥"}, {"question": "birth", "answer": "誕生"}, {"question": "bit", "answer": "少し"}, {"question": "black", "answer": "黒い"}, {"question": "blood", "answer": "血"}, {"question": "bloody", "answer": "血がついた"}, {"question": "blow", "answer": "吹き飛ばす"}, {"question": "blue", "answer": "青い"}, {"question": "boat", "answer": "ボート"}, {"question": "body", "answer": "体"}, {"question": "bone", "answer": "骨"}, {"question": "book", "answer": "本"}, {"question": "both", "answer": "両方"}, {"question": "bother", "answer": "悩ませる"}, {"question": "bottle", "answer": "ボトル"}, {"question": "bottom", "answer": "底"}, {"question": "box", "answer": "箱"}, {"question": "boy", "answer": "男の子"}, {"question": "bread", "answer": "パン"}, {"question": "break", "answer": "壊す"}, {"question": "breakfast", "answer": "朝食"}, {"question": "breath", "answer": "息"}, {"question": "bright", "answer": "明るい;"}, {"question": "bring", "answer": "持ってくる"}, {"question": "brother", "answer": "兄弟"}, {"question": "brown", "answer": "茶色の"}, {"question": "build", "answer": "建てる"}, {"question": "burn", "answer": "燃える"}, {"question": "bus", "answer": "バス"}, {"question": "business", "answer": "会社"}, {"question": "busy", "answer": "忙しい"}, {"question": "but", "answer": "でも"}, {"question": "buy", "answer": "買う"}, {"question": "buyer", "answer": "買い手"}, {"question": "by", "answer": "の近くに"}, {"question": "cake", "answer": "ケーキ"}, {"question": "camp", "answer": "キャンプ"}, {"question": "can", "answer": "することができる"}, {"question": "car", "answer": "車"}, {"question": "card", "answer": "カード"}, {"question": "care", "answer": "世話をする"}, {"question": "careful", "answer": "注意深い"}, {"question": "carefully", "answer": "注意深く"}, {"question": "carry", "answer": "運ぶ"}, {"question": "case", "answer": "場合"}, {"question": "cat", "answer": "猫"}, {"question": "catch", "answer": "捕まえる"}, {"question": "cause", "answer": "の原因となる"}, {"question": "center", "answer": "中心"}, {"question": "central", "answer": "中央の"}, {"question": "certain", "answer": "確信している"}, {"question": "certainly", "answer": "確かに"}, {"question": "chair", "answer": "椅子"}, {"question": "chance", "answer": "機会"}, {"question": "change", "answer": "変える"}, {"question": "charge", "answer": "請求する"}, {"question": "cheap", "answer": "安い"}, {"question": "check", "answer": "確認する"}, {"question": "chicken", "answer": "ニワトリ"}, {"question": "child", "answer": "子ども"}, {"question": "childhood", "answer": "子供時代"}, {"question": "chip", "answer": "削り取る"}, {"question": "choice", "answer": "選択"}, {"question": "choose", "answer": "選ぶ"}, {"question": "church", "answer": "教会"}, {"question": "city", "answer": "市"}, {"question": "class", "answer": "階級"}, {"question": "clean", "answer": "きれいな"}, {"question": "clear", "answer": "はっきりした"}, {"question": "clearly", "answer": "はっきりと"}, {"question": "climb", "answer": "登る"}, {"question": "clock", "answer": "時計"}, {"question": "close", "answer": "近い"}, {"question": "closely", "answer": "密接に"}, {"question": "clothes", "answer": "衣服"}, {"question": "clothing", "answer": "衣類"}, {"question": "club", "answer": "クラブ"}, {"question": "coat", "answer": "上着"}, {"question": "coffee", "answer": "コーヒー"}, {"question": "cold", "answer": "冷たい"}, {"question": "collect", "answer": "集める"}, {"question": "collection", "answer": "収集物"}, {"question": "college", "answer": "大学"}, {"question": "color", "answer": "色"}, {"question": "come", "answer": "行く"}, {"question": "comfort", "answer": "快適さ"}]
47 changes: 47 additions & 0 deletions kadai3/onoyama/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"./utils"
"fmt"
"os"
)

// 問題と解答のリスト
var json_path = "./json/words.json"

// タイムアウト設定
var timeout_seconds = 60

func main() {
var question utils.Question
questions := utils.LoadQuestions(json_path)
questioning := false
results := utils.Result{0, 0}

input_ch := utils.InputChannel(os.Stdin)
timeout_ch := utils.TimeoutChannel(timeout_seconds)

fmt.Printf("制限時間は、%d秒です。\n", timeout_seconds)

for {
select {
// 回答があっているかの確認
case answer := <-input_ch:
if result := utils.CheckAnswer(question, answer); result == true {
results.Correct++
}
questioning = false
case <-timeout_ch:
// タイムアウトで結果を表示
utils.ShowResult(results)
os.Exit(1)
default:
//質問がされていない場合は問題を出力
if !questioning {
results.Count++
question = utils.PopQuestion(questions, results.Count)
questioning = true
}
}
}
}
31 changes: 31 additions & 0 deletions kadai3/onoyama/utils/input_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package utils

import (
"bufio"
"io"
"time"
)

// 入力用のチャネル
func InputChannel(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
}

// タイムアウト用のチャネル
func TimeoutChannel(timeout int) <-chan bool {
ch := make(chan bool, 1)
go func() {
time.Sleep(time.Duration(timeout) * time.Second)
ch <- true
close(ch)
}()
return ch
}
67 changes: 67 additions & 0 deletions kadai3/onoyama/utils/question_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package utils

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"time"
)

// 質問格納用struct
type Question struct {
Question string `json:"question"`
Answer string `json:"answer"`
}

// 回答結果の格納用struct
type Result struct {
Count int
Correct int
}

// JSONファイルから問題をロード
func LoadQuestions(path string) []Question {
bytes, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
var questions []Question
if err := json.Unmarshal(bytes, &questions); err != nil {
log.Fatal(err)
}
return questions
}

// 問題の配列からランダムに一問抽出
func GetQuestion(questions []Question) Question {
rand.Seed(time.Now().UnixNano())
rand_index := rand.Intn(len(questions))
return questions[rand_index]
}

// 問題の表示
func PopQuestion(questions []Question, q_count int) Question {
question := GetQuestion(questions)
fmt.Printf("Q%d \"%s\" は日本語で? : ", q_count, question.Question)
return question
}

// 回答があっているか確認して結果を表示
func CheckAnswer(question Question, answer string) bool {
correct := false
if answer == question.Answer {
fmt.Printf("正解です!\n")
correct = true
} else {
fmt.Printf("不正解です。 正解は、\"%s\" です。\n", question.Answer)
}
return correct
}

// 正解の合計を表示
func ShowResult(result Result) {
fmt.Printf("\n!!! タイムオーバーです。!!!\n")
fmt.Printf("問題%d問中、正解は%d問でした。\n", result.Count, result.Correct)
}
142 changes: 142 additions & 0 deletions kadai3/onoyama/utils/question_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package utils

import (
"bytes"
"fmt"
"io"
"os"
"testing"
)

// テスト問題用のJSONファイル
var test_json_path = "../json/questions.json"
var questions []Question

// テスト用問題の解答
var expect_questions = []Question{
Question{"test1", "テスト1"},
Question{"test2", "テスト2"},
Question{"test3", "テスト3"},
}

// 問題のロードのテスト
func TestLoadQuestions(t *testing.T) {
questions = LoadQuestions(test_json_path)
expect_len := 3
if actual_len := len(questions); expect_len != actual_len {
t.Error(`expect="%s" actual="%s"`, expect_len, actual_len)
}
for i, question := range questions {
if expect_questions[i] != question {
t.Error(`expect="%s" actual="%s"`, expect_questions[i], question)
}
}
}

// 問題の解答が正しいかテスト
func TestGetQuestion(t *testing.T) {
question := GetQuestion(questions)
is_question := false
for _, expect := range expect_questions {
if question.Question == expect.Question {
if question.Answer != expect.Answer {
t.Error(`expect="%s" actual="%s"`, expect.Answer, question.Answer)
}
is_question = true
}
}
if !is_question {
t.Error(`Invalid question : "%v"`, question)
}
}

// 問題の表示が正しいかテスト
func TestPopQuestion(t *testing.T) {
out := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
expect_question := PopQuestion(questions, 5)
expect := fmt.Sprintf("Q%d \"%s\" は日本語で? : ", 5, expect_question.Question)
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
w.Close()
os.Stdout = out
actual := <-outC

if actual != expect {
t.Errorf(`expect="%s" actual="%s"`, expect, actual)
}
}

// 回答が正解の場合の表示のテスト
func TestCheckAnswer1(t *testing.T) {
question := GetQuestion(questions)
expect := fmt.Sprintf("正解です!\n")
out := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
CheckAnswer(question, question.Answer)
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
w.Close()
os.Stdout = out
actual := <-outC

if actual != expect {
t.Errorf(`expect="%s" actual="%s"`, expect, actual)
}
}

// 回答が不正解の場合のテスト
func TestCheckAnswer2(t *testing.T) {
question := GetQuestion(questions)
expect := fmt.Sprintf("不正解です。 正解は、\"%s\" です。\n", question.Answer)
out := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
CheckAnswer(question, "xxxxxxxxxxxx")
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
w.Close()
os.Stdout = out
actual := <-outC

if actual != expect {
t.Errorf(`expect="%s" actual="%s"`, expect, actual)
}
}

// タイムアウト後の結果表示のテスト
func TestShowResult(t *testing.T) {
expect_result := Result{10, 5}
expect := fmt.Sprintf("\n!!! タイムオーバーです。!!!\n問題%d問中、正解は%d問でした。\n", expect_result.Count, expect_result.Correct)
out := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
ShowResult(expect_result)
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
w.Close()
os.Stdout = out
actual := <-outC

if actual != expect {
t.Errorf(`expect="%s" actual="%s"`, expect, actual)
}
}