ゲームのBrushUp ~Pythonで百人一首クイズを作ろう ep 3~

python
python

百人一首クイズゲームができた!!

ここからブラシュアップしていこう!!

記事①:ローカルとweb上のcsvファイルを読み込む ~Pythonで百人一首クイズを作ろう ep 1~
記事②:classを使おう!さらにゲームの完成へ ~Pythonで百人一首クイズを作ろう ep 2~

前回、「百人一首クイズゲーム」を完成させました!
今回は、作ってみて気になった点を改善(+アレンジ)していきたいと思います。
(2021年3月29日:学習開始38日目 PyQさんで勉強中!

オンラインPython学習サービス「PyQ™(パイキュー)」


ep 1で映画「ちはやふる」の話をしましたが、この映画「上の句」「下の句」「結び」の3本が公開されています。
この3本に優劣をつける必要がないくらい(某ターミネーターとは違うのです!)傑作ですが、ここでは「ちはやふるー結びー」の魅力を話たいと思います。
完結編にあたる「結び」は高校3年生の主人公たちを描いています。前2作が高校1年生の時を描いているので2年後です。この間リアルタイムで約2年たっているので、広瀬すずさんをはじめキャストが2年大人になっており、違和感なくストーリーに入っていけるんですね。

キャスト本人たちが2年間演技に磨きをかけたのと、ストーリー上2年間競技かるたに情熱を燃やしたのがリンクして、表情から熱量まですべてが「成長」しています
ストーリーもとにかく熱く、高3、卒業ですよ?泣けるにきまってるじゃないですか!

これ以上語ると、それで終わってしまいそうなのでこれくらいで止めておきます。


この「ちはやふるー結びー」で主題歌に使われたのが前作同様Perfumeさんの「無限未来」です。
また、この曲が映画にあってるんですよ。(曲名から公式YouTubeに飛びます。)

さて、この「百人一首クイズゲーム」づくりも「結び」に取り掛かりしょう。
(最終形態は、このページの一番下にあります。完成品です!)

1.前回の振り返りと今回やりたい事

冒頭にも書いてきましたが、前回、「百人一首クイズゲーム」を完成させました。
一度、前回のプログラムを転記します。

import random #randomをインポート

class Issyu:
    def __init__(self, num, kajin ='', kami_kanji='', shimo_kanji='', kami_hiragana='', shimo_hiragana=''):
        self.num = num #No
        self.kajin = kajin #歌人
        self.kami_kanji = kami_kanji #上の句(漢字)
        self.shimo_kanji = shimo_kanji #下の句(漢字)
        self.kami_hiragana = kami_hiragana #上の句(ひらがな)
        self.shimo_hiragana = shimo_hiragana #下の句(ひらがな)
    
    def syutudai(self): #出題を定義
        return f'問題!上の句:{self.kami_hiragana}'
    
    def kaitou(self,num):
        return f'{num} : {self.shimo_hiragana}'

hyakunin_dict ={} #辞書を定義

with open('C:/Users/xxxx/yyyy/hyakunin.csv', 'r', encoding='shift_jis') as f: #「hyakunin.csv」を開く
    for row in f:
        hyakunin_list = row.strip().split(',') #空白の削除とカンマでの区切り
        try:
            waka_num = int(hyakunin_list[0]) #No数字に
            waka_kajin = hyakunin_list[1] #歌人
            waka_k_k = hyakunin_list[2] #上の句(漢字)
            waka_s_k = hyakunin_list[3] #下の句(漢字)
            waka_k_h = hyakunin_list[4] #上の句(ひらがな)
            waka_s_h = hyakunin_list[5] #下の句(ひらがな)
            hyakunin_dict[waka_num] = Issyu(waka_num, waka_kajin, waka_k_k, waka_s_k, waka_k_h, waka_s_h)
        except ValueError:
            pass

def kaitou_input():
    while True:
        kaitou_no = input('回答:')
        if kaitou_no in ['1', '2', '3', '4', '5']: #1~5が入力された場合
            return kaitou_no #文字列の1~5を返す。
            break #ループから抜ける。
        else:
            print('1~5から選んでください') #1~5以外が入力された場合
        
def main_game():
    print('百人一首クイズ!')
    num_list = list(range(1,101)) #1~100の数字リストを作成
    while True:
        if num_list == []:  #100首すべて終了
            print('全問終了です!!')
            break
        print(f'残り{len(num_list)}問') #残り問題数を表示
        mondai_no = random.choice(num_list) #問題のNoをランダム選択
        mondai_waka = hyakunin_dict[mondai_no] #問題の和歌を定義
        print(mondai_waka.syutudai()) #出題
        huseikai_list = list(range(1,101)) #不正解の和歌番号リスト
        huseikai_list.remove(mondai_no) #不正解リストから正解の1首を除去
        kaitou_list = list(range(1,6)) #解答番号のリスト作成
        seikai_no = random.choice(kaitou_list) #正解の番号
        for row in kaitou_list:
            if row == seikai_no: #正解の番号の場合
                print(mondai_waka.kaitou(row)) #正解の下の句を表示
            else:
                huseikai_no = random.choice(huseikai_list) #不正解の和歌Noをランダム選択
                huseikai_waka = hyakunin_dict[huseikai_no] #不正解の和歌Noを定義
                print(huseikai_waka.kaitou(row)) #不正解の下の句を表示
                huseikai_list.remove(huseikai_no) #不正解の和歌Noの選択肢を除去
        print('正解は?1~5から選んでください')
        #print(f'答えは{seikai_no}') #カンニング
        kaitou_no = kaitou_input() #回答Noをインプット
        if kaitou_no == str(seikai_no): #回答Noと正解のNoが同じ
            print('正解!!')
            num_list.remove(mondai_no) #1~100のリストから、問題Noを除去
        else: #回答Noと正解のNoが異なる
            print(f'不正解!!正解は {seikai_no} 番')

main_game()

クイズゲームとしては成り立っているのですが、いくつか不満な点があります。
以下に改善点をまとめました。

4つの改善点をあげました。

①はそのまま、途中で中止できるプログラムを入れたいと思います。

②は、実際にやってみると、ひらがなが読みにくかったです。
開始前に「ひらがな」と「漢字」のどちらにするかを選択するプログラムを入れたいと思います。

③は、パッと表示されてパッと回答していうのに情緒が無いように感じました。
実際の「かるたとり」のように、出題を工夫したいと思います。

④は、せっかくなので、「歌人から和歌をあてる」、とか「和歌から歌人をあてる」といったモードに変更できるプログラムを入れたいと思います。

では、一つずつやっていきましょう!

2.改善プログラム① ~途中で止めにけり~

作ってやってみた感想で、最初に思ったのは「100問はきつい!」でした。
どこかでこちらからでSTOPをかけたいと思いますが、指示をだせるとすると回答を入力するタイミングだと思います。
(ctrl + cでも止めれますが、プログラミングやったことなければ無理でしょう。)

ではやっていきたいと思います。変更点は3か所です。
①:入力で「stop」と入力できるようする。(いままでは1~5以外受け付けなかった)
②:入力を促す表示に 「※途中で終了する場合は「stop」」を加える。
③:「stop」と入力された場合に終了させる。

~~~~~略~~~~~
def kaitou_input():
    while True:
        kaitou_no = input('回答:')
        if kaitou_no in ['1', '2', '3', '4', '5']: #1~5が入力された場合
            return kaitou_no #文字列の1~5を返す。
            break #ループから抜ける。
        elif kaitou_no == 'stop':
            return 'stop' #stopと入力された場合stopを返す
            break #ループから抜ける。
        else:
            print('1~5から選んでください') #1~5以外が入力された場合

def main_game():
    print('百人一首クイズ!')
~~~~~略~~~~~
        print('正解は?1~5から選んでください ※途中で終了する場合は「stop」')
        #print(f'答えは{seikai_no}') #カンニング
        kaitou_no = kaitou_input() #回答Noをインプット
        if kaitou_no == str(seikai_no): #回答Noと正解のNoが同じ
            print('正解!!')
            num_list.remove(mondai_no) #1~100のリストから、問題Noを除去
        elif kaitou_no == 'stop':
            print('終了します')
            break
        else: #回答Noと正解のNoが異なる
            print(f'不正解!!正解は {seikai_no} 番')

main_game()

それでは、動かしてみましょう。回答時に「stop」と入力してみます。

百人一首クイズ!
残り100問
問題!上の句:あひみてののちのこころにくらぶれば
1 : ひとのいのちのをしくもあるかな
2 : ひとをもみをもうらみざらまし
3 : ぬれにぞぬれしいろはかはらず
4 : むかしはものをおもはざりけり
5 : うしとみしよぞいまはこひしき
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:stop
終了します

できました!!この変更は簡単でしたね!

では、次に行きましょう。

3.改善プログラム② ~ひらがな、漢字選びたきかな~

つぎに、出題、回答を「ひらがな」か「漢字」かを選べるようにしたいと思います。

現在のプログラムでは、この選択をするタイミングはなさそうです。
ですので、ゲーム開始時にモード選択できるようなパートを加えたいと思います。
また、現行では、問題および回答の定義は「class Issyu」内で定められているのでここも改変する必要がありそうです。
しかし、ゲーム本体関数(=main_game())では、意外と表示には関与していなさそうです。
main_gameの編集は必要最低限として、やってみようと思います。

ここまでを踏まえてやっていきます。変更点は3箇所です。
①:表示モード選択関数mode_inputを定義、「ひらがな」か「漢字」を返す
②:Issyu クラスのsyutudai定義とkaitou定義を変更。mode_inputの選択を反映する。
③:①、②に合わせて、main_game関数を編集する。

import random #randomをインポート

class Issyu:
~~~~~略~~~~~
    def syutudai(self, mode = ''): #出題を定義 表示モード = mode
        if mode == 'kanji':
            return f'問題!上の句:{self.kami_kanji}' #漢字上の句
        else:
            return f'問題!上の句:{self.kami_hiragana}' #hひらがな上の句
    
    def kaitou(self, num , mode = ''): #回答を定義 表示モード = mode
        if mode == 'kanji':
            return f'{num} : {self.shimo_kanji}' #漢字下の句
        else:
            return f'{num} : {self.shimo_hiragana}' #hひらがな下の句
~~~~~略~~~~~
def mode_input():
    while True:
        print('表示モードを選択してください:ひらがな → 1 、漢字 → 2')
        mode_choise = input('表示モード:')
        if mode_choise == '1':
            return 'hiragana'
            break
        elif mode_choise == '2':
            return 'kanji'
            break
        else:
            pass
        
def main_game():
    print('百人一首クイズ!')
    num_list = list(range(1,101)) #1~100の数字リストを作成
    mode = mode_input() #表示モード選択
~~~~~略~~~~~
        mondai_waka = hyakunin_dict[mondai_no] #問題の和歌を定義
        print(mondai_waka.syutudai(mode)) #出題
        huseikai_list = list(range(1,101)) #不正解の和歌番号リスト
~~~~~略~~~~~
        for row in kaitou_list:
            if row == seikai_no: #正解の番号の場合
                print(mondai_waka.kaitou(row, mode)) #正解の下の句を表示
            else:
                huseikai_no = random.choice(huseikai_list) #不正解の和歌Noをランダム選択
                huseikai_waka = hyakunin_dict[huseikai_no] #不正解の和歌Noを定義
                print(huseikai_waka.kaitou(row, mode)) #不正解の下の句を表示
                huseikai_list.remove(huseikai_no) #不正解の和歌Noの選択肢を除去

では出力してみましょう。

百人一首クイズ!
表示モードを選択してください:ひらがな → 1 、漢字 → 2
表示モード:p
表示モードを選択してください:ひらがな → 1 、漢字 → 2
表示モード:2
残り100問
問題!上の句:もろともにあはれと思え山桜
1 : 逢はでこの世を過ぐしてよとや
2 : まつとし聞かば今帰り来む
3 : 花よりほかに知る人もなし
4 : 有明の月を待ち出でつるかな
5 : もれ出づる月の影のさやけさ
正解は?1~5から選んでください ※途中で終了する場合は「stop」

うまくできました。
1,2以外がインプットされたらループしています。
2がインプットされた場合、漢字表示になっています。
(ちなみに1の場合はひらがなのままでした。)

ところで、今回は出題と回答、両方が「ひらがな」か「漢字」となっています。
出題は「漢字」、回答は「ひらがな」みたいな事も可能、というかやることは同じですし、無駄に長くなるので止めておきます。

次に行きましょう!

4.改善プログラム③ ~情緒とともに出しつきかも~

なんか情緒がないのをどうにかしたいと思います。なぜ情緒がないのか?
なんか、パッ、パッと一瞬で表示されて「かるた読み上げ感」がないのが原因です。
上の句を一文字ずつゆっくり表示させれないでしょうか?

ん?ゆっくり表示?どうやるのでしょうか?
調べてみると、TeckAcademyさんのこちらの記事が見つかりました。
処理を一時停止!Pythonでsleepを使う方法【初心者向け】

少し自分でも少し試してみましょう!

import time

for i in 'あいうえお':
    time.sleep(1)
    print(i)

結果はこうなります。

あ
い
う
え
お

確かに1秒ごとにあ、い、う、え、お、が表示されます。
ただ、改善すべき点が3つあります。
①:縦に表示=一文字ごとに改行されている →print (i, end = ”)で改行なし、最後に改行追加
②:最初の1文字の前のsleepが邪魔 →printとtime.sleepを入れ替え。(本編では入れ替えず)
③:1秒は長すぎる。→ いろいろ試して0.25秒くらいがちょうど良い

①~③を踏まえて修正しました。

import time

for i in 'あいうえお':
    print(i, end = '') #改行を削除
    time.sleep(0.25) #0.25秒間隔
print('') #最後に改行

結果はこうなります。(動画じゃないとわからないですが、面倒なので動画にはしません笑)

あいうえお

ダメです。感覚としては、0.25秒X5の1.25秒が経過した後にすべていっきに表示されています。
うーん、、、end=”を入れる前はきちんと表示されていました。
調べてみると、英語で質問しているのがみつかりました。こちらです。
printの中に、flush = Trueを入れればよいと書いています。

import time

for i in 'あいうえお':
    print(i,end ='', flush = True) #改行を削除
    time.sleep(0.25) #0.25秒間隔
print('') #最後に改行

うまくできています。このテクニックを使って、反映させたいと思います。

ちなみに、なにが起きているかというと、処理が終わるのを待ってまとめて表示しているようです。
flush = Trueをつけると即時表示を指示しているようです。
こちらを参照しました。ほかの対処法も紹介されています。
pythonで print の出力結果を即時表示, 強制表示, フラッシュさせる(主にjupyter)

ところで、time.sleep(0)とすれば今までどおりパッ、パッと表示されるはずです。
今までどおり表示とするかゆっくり表示するかを選べるようにしたいと思います。
あらたにゆっくり表示選択関数を定義して、選択できるようにしたいと思います。
「ゆっくり表示」は、Issyu クラスのsyutudai定義を編集します。

ここまでを踏まえてやっていきます。変更点は3箇所です。
①:ゆっくり表示選択関数yukkuri_inputで「ゆっくり表示モード」を選択できるようにする。
②:Issyu クラスのsyutudai定義を変更する。
③:①、②に合わせて、main_game関数を編集する。

import random #randomをインポート
import time #timeをインポート

class Issyu:
~~~~~略~~~~~
    def syutudai(self, mode = '', gap =0): #出題を定義 表示モード = mode ゆっくり表示gap
        if mode == 'kanji':
            print('問題!上の句:', end = '') #改行を除外
            for i in self.kami_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print('') #最後の改行
        else:
            print('問題!上の句:', end = '')
            for i in self.kami_hiragana:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #hひらがな上の句
            print('') #最後の改行

def main_game():
    print('百人一首クイズ!')
    num_list = list(range(1,101)) #1~100の数字リストを作成
    mode = mode_input() #表示モード選択
    time_gap = yukkuri_input() #ゆっくり表示選択
~~~~~略~~~~~
        mondai_waka = hyakunin_dict[mondai_no] #問題の和歌を定義
        mondai_waka.syutudai(mode, time_gap) #出題 mode = 表示モード、time_gap = 表示速度
        huseikai_list = list(range(1,101)) #不正解の和歌番号リスト
~~~~~略~~~~~

表示してみましょう。

百人一首クイズ!
表示モードを選択してください:ひらがな → 1 、漢字 → 2
表示モード:2
ゆっくり表示モードにする?:はい → 1 、いいえ → 2
ゆっくり表示モード選択:1
残り100問
問題!上の句:ひさかたの光のどけき春の日に
1 : 人づてならでいふよしもがな
2 : しづ心なく花の散るらむ
3 : 流れもあへぬ紅葉なりけり
4 : 海人の小舟の綱手かなしも
5 : 乙女の姿しばしとどめむ
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:stop
終了します

伝わらないですが、うまく行きました。改行等も違和感ないですね。
いっきに情緒が出てきました。

次に行きましょう。

5.改善プログラム④ ~和歌と歌人も覚えたきかな~

さて、次は別のゲームにしてしまうという話です。
追加したいのは、「歌人→和歌モード」と「和歌→歌人モード」です。
ややこしいので、このモードでは和歌は漢字表示固定で行きます。
結構な大改編になってしまうのでしょうか?考えていきましょう。

ゲームの選択は、表示モード選択関数mode_inputを編集すれば出来そうです。
それで、この関数から受け取ったreturnで表示がきまります。
表示はIssyuクラスの中の関数で決めているので、ここを変えればできそうです。

あれ?これだけで行けるか?やってみましょう。
変更点は4箇所です。
①:表示モード選択関数mode_inputに「歌人→和歌モード」と「和歌→歌人モード」を加える。
②:Issyu クラスのsyutudai定義を、①のモードに合わせて表示するように変更する。
③:Issyu クラスのkaitou定義を、①のモードに合わせて表示するように変更する。
④:①、②、③に合わせて、main_game関数を編集する。(編集なしでいけました!)

import random #randomをインポート
import time #timeをインポート

class Issyu:
~~~~~略~~~~~
    def syutudai(self, mode = '', gap =0): #出題を定義 表示モード = mode ゆっくり表示gap
        if mode == 'kanji':
            print('問題!上の句:', end = '') #改行を除外
            for i in self.kami_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print('') #最後の改行
        elif mode == 'hiragana':
            print('問題!上の句:', end = '')
            for i in self.kami_hiragana:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #hひらがな上の句
            print('') #最後の改行
        elif mode == 'kajin':
            print('問題!歌人:', end = '') #改行を除外
            for i in self.kajin:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print('') #最後の改行
        else: #modeがwakaの場合
            print('問題!和歌:', end = '') #改行を除外
            for i in self.kami_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print(' ', end = '') #上の句と下の句の間にスペース
            for i in self.shimo_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句            
            print('') #最後の改行 
    
    def kaitou(self, num , mode = ''): #回答を定義 表示モード = mode
        if mode == 'kanji':
            return f'{num} : {self.shimo_kanji}' #漢字下の句
        elif mode == 'hiragana':
            return f'{num} : {self.shimo_hiragana}' #hひらがな下の句
        elif mode == 'kajin': #modeが歌人の場合、回答は和歌
            return f'{num} : {self.kami_kanji} {self.shimo_kanji}' #漢字和歌
        else: #modeが和歌の場合、回答は歌人
            return f'{num} : {self.kajin}' #h歌人
~~~~~略~~~~~
def mode_input(): #表示モード選択関数
    print('ゲームモードを選択してください。')
    print('かるた取り: 1 , 「歌人から和歌をあてる」: 2 , 「和歌から歌人をあてる」: 3')
    while True:
        mode_choise = input('ゲームモード:')
        if mode_choise == '2':
            return 'kajin'
            break
        elif mode_choise == '3':
            return 'waka'
            break
        elif mode_choise == '1':
            while True:
                print('表示モードを選択してください:ひらがな → 4 、漢字 → 5')
                mode_choise = input('表示モード:')
                if mode_choise == '4':
                    return 'hiragana'
                    break
                elif mode_choise == '5':
                    return 'kanji'
                    break
                else:
                    pass #1か2以外がインプットされた場合戻る
        else:
            print('1~3でモードを選択')
~~~~~略~~~~~

では実行してみましょう。まず、モード2です。

百人一首クイズ!
ゲームモードを選択してください。
かるた取り: 1 , 「歌人から和歌をあてる」: 2 , 「和歌から歌人をあてる」: 3
ゲームモード:2
ゆっくり表示モードにする?:はい → 1 、いいえ → 2
ゆっくり表示モード選択:2
残り100問
問題!歌人:前大僧正行尊
1 : 小倉山峰のもみぢ葉心あらば 今ひとたびのみゆき待たなむ
2 : 心にもあらで憂き夜にながらへば 恋しかるべき夜半の月かな
3 : わたの原漕ぎ出でて見ればひさかたの 雲居にまがふ沖つ白波
4 : 君がため春の野に出でて若菜摘む わが衣手に雪は降りつつ
5 : もろともにあはれと思え山桜 花よりほかに知る人もなし
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:1
不正解!!正解は 5 番
残り100問
問題!歌人:清少納言
1 : 恋すてふわが名はまだき立ちにけり 人知れずこそ思ひそめしか
2 : わびぬれば今はた同じ難波なる 身をつくしても逢はむとぞ思ふ
3 : 契りおきしさせもが露を命にて あはれ今年の秋もいぬめり
4 : 夜をこめて鳥のそら音ははかるとも よに逢坂の関はゆるさじ
5 : もろともにあはれと思え山桜 花よりほかに知る人もなし
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:

次にモード3でも実行してみます。

百人一首クイズ!
ゲームモードを選択してください。
かるた取り: 1 , 「歌人から和歌をあてる」: 2 , 「和歌から歌人をあてる」: 3
ゲームモード:3
ゆっくり表示モードにする?:はい → 1 、いいえ → 2
ゆっくり表示モード選択:1
残り100問
問題!和歌:嘆きつつひとり寝る夜の明くる間は いかに久しきものとかは知る
1 : 中納言兼輔
2 : 右大将道綱母
3 : 儀同三司母
4 : 清原深養父
5 : 大納言経信
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:1
不正解!!正解は 2 番
残り100問
問題!和歌:世の中は常にもがもな渚漕ぐ 海人の小舟の綱手かなしも
1 : 崇徳院
2 : 大中臣能宣
3 : 安倍仲麻呂
4 : 鎌倉右大臣
5 : 権中納言定頼
正解は?1~5から選んでください ※途中で終了する場合は「stop」
回答:

出来ています!!!

これでやりたかった事はすべてできました!!
一番下に省略なしのすべてをまとめたプログラムを置いています。

FIN

PyQさんで勉強中!

プログラム完成品

import random #randomをインポート
import time #timeをインポート

class Issyu:
    def __init__(self, num, kajin ='', kami_kanji='', shimo_kanji='', kami_hiragana='', shimo_hiragana=''):
        self.num = num #No
        self.kajin = kajin #歌人
        self.kami_kanji = kami_kanji #上の句(漢字)
        self.shimo_kanji = shimo_kanji #下の句(漢字)
        self.kami_hiragana = kami_hiragana #上の句(ひらがな)
        self.shimo_hiragana = shimo_hiragana #下の句(ひらがな)
    
    def syutudai(self, mode = '', gap =0): #出題を定義 表示モード = mode ゆっくり表示gap
        if mode == 'kanji':
            print('問題!上の句:', end = '') #改行を除外
            for i in self.kami_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print('') #最後の改行
        elif mode == 'hiragana':
            print('問題!上の句:', end = '')
            for i in self.kami_hiragana:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #hひらがな上の句
            print('') #最後の改行
        elif mode == 'kajin':
            print('問題!歌人:', end = '') #改行を除外
            for i in self.kajin:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print('') #最後の改行
        else: #modeがwakaの場合
            print('問題!和歌:', end = '') #改行を除外
            for i in self.kami_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句
            print(' ', end = '') #上の句と下の句の間にスペース
            for i in self.shimo_kanji:
                time.sleep(gap) #gap秒間隔で表示
                print(i, end ='', flush = True) #漢字上の句            
            print('') #最後の改行 
    
    def kaitou(self, num , mode = ''): #回答を定義 表示モード = mode
        if mode == 'kanji':
            return f'{num} : {self.shimo_kanji}' #漢字下の句
        elif mode == 'hiragana':
            return f'{num} : {self.shimo_hiragana}' #hひらがな下の句
        elif mode == 'kajin': #modeが歌人の場合、回答は和歌
            return f'{num} : {self.kami_kanji} {self.shimo_kanji}' #漢字和歌
        else: #modeが和歌の場合、回答は歌人
            return f'{num} : {self.kajin}' #h歌人

hyakunin_dict ={} #辞書を定義

with open('C:/Users/xxxx/yyyy/hyakunin.csv', 'r', encoding='shift_jis') as f: #「hyakunin.csv」を開く
    for row in f:
        hyakunin_list = row.strip().split(',') #空白の削除とカンマでの区切り
        try:
            waka_num = int(hyakunin_list[0]) #No数字に
            waka_kajin = hyakunin_list[1] #歌人
            waka_k_k = hyakunin_list[2] #上の句(漢字)
            waka_s_k = hyakunin_list[3] #下の句(漢字)
            waka_k_h = hyakunin_list[4] #上の句(ひらがな)
            waka_s_h = hyakunin_list[5] #下の句(ひらがな)
            hyakunin_dict[waka_num] = Issyu(waka_num, waka_kajin, waka_k_k, waka_s_k, waka_k_h, waka_s_h)
        except ValueError:
            pass

def kaitou_input():
    while True:
        kaitou_no = input('回答:')
        if kaitou_no in ['1', '2', '3', '4', '5']: #1~5が入力された場合
            return kaitou_no #文字列の1~5を返す。
            break #ループから抜ける。
        elif kaitou_no == 'stop':
            return 'stop' #stopと入力された場合stopを返す
            break #ループから抜ける。
        else:
            print('1~5から選んでください') #1~5以外が入力された場合

def mode_input(): #表示モード選択関数
    print('ゲームモードを選択してください。')
    print('かるた取り: 1 , 「歌人から和歌をあてる」: 2 , 「和歌から歌人をあてる」: 3')
    while True:
        mode_choise = input('ゲームモード:')
        if mode_choise == '2':
            return 'kajin'
            break
        elif mode_choise == '3':
            return 'waka'
            break
        elif mode_choise == '1':
            while True:
                print('表示モードを選択してください:ひらがな → 4 、漢字 → 5')
                mode_choise = input('表示モード:')
                if mode_choise == '4':
                    return 'hiragana'
                    break
                elif mode_choise == '5':
                    return 'kanji'
                    break
                else:
                    pass #1か2以外がインプットされた場合戻る
        else:
            print('1~3でモードを選択')
        
def yukkuri_input(): #ゆっくり表示選択関数
    while True:
        print('ゆっくり表示モードにする?:はい → 1 、いいえ → 2')
        yukkuri_choise = input('ゆっくり表示モード選択:')
        if yukkuri_choise == '1': #ゆっくり表示モードはい
            return 0.25 #0.25を返す
            break
        elif yukkuri_choise == '2': #ゆっくり表示モードいいえ
            return 0 #0を返す
            break
        else:
            pass #1か2以外がインプットされた場合戻る
        
def main_game():
    print('百人一首クイズ!')
    num_list = list(range(1,101)) #1~100の数字リストを作成
    mode = mode_input() #表示モード選択
    time_gap = yukkuri_input() #ゆっくり表示選択
    while True:
        if num_list == []:  #100首すべて終了
            print('全問終了です!!')
            break
        print(f'残り{len(num_list)}問') #残り問題数を表示
        mondai_no = random.choice(num_list) #問題のNoをランダム選択
        mondai_waka = hyakunin_dict[mondai_no] #問題の和歌を定義
        mondai_waka.syutudai(mode, time_gap) #出題 mode = 表示モード、time_gap = 表示速度
        huseikai_list = list(range(1,101)) #不正解の和歌番号リスト
        huseikai_list.remove(mondai_no) #不正解リストから正解の1首を除去
        kaitou_list = list(range(1,6)) #解答番号のリスト作成
        seikai_no = random.choice(kaitou_list) #正解の番号
        for row in kaitou_list:
            if row == seikai_no: #正解の番号の場合
                print(mondai_waka.kaitou(row, mode)) #正解の下の句を表示
            else:
                huseikai_no = random.choice(huseikai_list) #不正解の和歌Noをランダム選択
                huseikai_waka = hyakunin_dict[huseikai_no] #不正解の和歌Noを定義
                print(huseikai_waka.kaitou(row, mode)) #不正解の下の句を表示
                huseikai_list.remove(huseikai_no) #不正解の和歌Noの選択肢を除去
        print('正解は?1~5から選んでください ※途中で終了する場合は「stop」')
        #print(f'答えは{seikai_no}') #カンニング
        kaitou_no = kaitou_input() #回答Noをインプット
        if kaitou_no == str(seikai_no): #回答Noと正解のNoが同じ
            print('正解!!')
            num_list.remove(mondai_no) #1~100のリストから、問題Noを除去
        elif kaitou_no == 'stop':
            print('終了します')
            break
        else: #回答Noと正解のNoが異なる
            print(f'不正解!!正解は {seikai_no} 番')

main_game()

最終的に、157行!!!冒頭のプログラムが75行なのでいろいろやった結果倍以上になってます。
けど、長いって別に良いことではないからなぁ。

まあ、やりたいことは、できたしこれにて終了!めでたしめでたし。

FIN

PyQさんで勉強中!

コメント

タイトルとURLをコピーしました