【Python】マッチ棒クイズ開発 Part12

こんにちは、にわこまです。

今回は、問題を表示する関数と問題をセットする関数の作成を行います。問題を表示するとは文字通りであり、「3 – 6 = 8」のような問題を表示します。問題をセットするとは、新たな問題を代入し、表示することです。

 

誤字脱字や分からない点がございましたらご連絡お願いいたします!

メールまたはTwitterのDMまで!!

 

 

 

スポンサードサーチ


問題を表示する関数の作成

この関数は、前回Part11で作成したマッチ棒枠を表示する関数の問題バージョンであるとイメージしていただけると、想像しやすいと思います。

「3 – 6 = 8」というような問題の座標を計算し、マッチ棒を表示していくという関数になります。

 

 

コードの提示

問題を表示する関数のソースコードを以下に示します。

import kivy
kivy.require("2.0.0")

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.graphics import Rotate
from kivy.graphics.context_instructions import PushMatrix, PopMatrix

import numpy as np

class MatchStickWidget(Widget):
    # 省略

class MatchStickFrameWidget(Widget):
    # 省略

class PlayFieldWidget(FloatLayout):
    def __init__(self, **kwargs):
        # 省略
    def on_size(self, *args):
        self.base_x = self.center_x - (45 * self.ms_w) / 2
        self.base_y = self.center_y - (17 * self.ms_w) / 2
        self.bg_rect.size = self.size
        self.drawFrame()
        self.drawQuestion() # Added
    def calcPos(self, base_x, base_y, k, *args):
        # 省略
    def drawFrame(self, *args):
        # 省略
    def drawQuestion(self, *args):
        if(len(self.msDict) == 0):
            for idx, k in enumerate(self.quesList):
                pos_list = self.calcPos(self.base_x+idx*(self.ms_w+self.ms_h+self.ms_w), self.base_y, k)
                for pos_t in pos_list:
                    obj = MatchStickWidget(pos=[pos_t[0], pos_t[1]], ms_w=self.ms_w, angle=pos_t[2])
                    self.msDict[obj] = ([pos_t[0], pos_t[1]], pos_t[0], pos_t[1], pos_t[2])
                    self.add_widget(obj)
        elif(len(self.msDict) != 0):
            tempmsList = list(self.msDict.keys())
            c = 0       # index of tempmsList
            for idx, k in enumerate(self.quesList):
                pos_list = self.calcPos(self.base_x+idx*(self.ms_w+self.ms_h+self.ms_w), self.base_y, k)
                for pos_t in pos_list:
                    obj = tempmsList[c]
                    obj.ms_w = self.ms_w
                    obj.pos = [pos_t[0], pos_t[1]]
                    obj.angle = pos_t[2]
                    self.msDict[obj] = ([pos_t[0], pos_t[1]], pos_t[0], pos_t[1], pos_t[2])
                    c += 1

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Color(rgb=[1, 1, 1])
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
    def on_size(self, *args):
        self.bg_rect.size = self.size

class MatchStickQuizApp(App):
    def build(self):
        root = RootWidget()
        pfw = PlayFieldWidget()
        pfw.quesList = ["3", "-", "6", "=", "8"]
        root.add_widget(pfw)
        return root

if __name__ == '__main__':
    MatchStickQuizApp().run()
    pass

 

上記のコードは以下からダウンロードできます。

 

 

コードの解説

27行目の「self.darwQuestion()」は、後述する問題を表示する関数を実行しています。

 

 

32行目から51行目の「drawQuestion関数」は、問題を表示する関数です。

 

33行目の「if文」は、「msDictが空であるか」を判別する条件式です。

 

34行目の「for文」は、quesListの要素数だけ繰り返します。また、enumerate関数によって繰り返しているため、取得した要素のインデックスも取得しています。

 

35行目の「pos_list」は、calcPosによって計算した座標を代入する変数です。

x座標についてはPart11で解説したため割愛します。

 

36行目の「for文」は、座標の数だけ繰り返す処理です。

 

37行目の「obj」は、マッチ棒のクラスに座標とマッチ棒の横幅、角度を代入して生成したオブジェクトを代入する変数です。

 

38行目は、キーにマッチ棒、値に座標や角度を代入し保持する変数です。

 

39行目の「self.add_widget(obj)」は、PlayFieldWidget自体に追加することでマッチ棒を表示しています。

 

 

40行目の「if文」は、「msDictが空でない」を判別する条件式です。

 

41行目の「tempList」は、msDictのキーだけをリスト型に変形し代入する変数です。

 

42行目の「c」は、tempListからオブジェクトを取り出すためのインデックスを代入する変数です。

 

43行目の「for文」は、quesListの要素数だけ繰り返します。また、enumerate関数によって繰り返しているため、取得した要素のインデックスも取得しています。(34行目と同じです。)

 

44行目の「pos_list」は、calcPosによって計算した座標を代入する変数です。(35行目と同じです。)

x座標についてはPart11で解説したため割愛します。

 

45行目の「for文」は、座標の数だけ繰り返す処理です。(36行目と同じです。)

 

46行目の「obj」は、tempListから取り出したオブジェクトを代入する変数です。

 

47行目の「obj.ms_w」は、マッチ棒枠の横幅を代入する変数です。

 

48行目の「obj.pos」は、新たな座標を代入する変数です。

 

49行目の「obj.angle」は、新たな角度を代入する変数です。

 

50行目は、objの値を新しい値に更新しています。

 

51行目の「c += 1」は、cに1足しています。

  

 

動作確認

コードを保存したら、コマンドプロンプトを開きファイルを保存したフォルダまで移動します。移動したら、以下のコマンドを入力し実行します。

python matchstickquiz.py

 

ウィンドウを最大化し、以下のように表示されれば動作確認完了です。

  

 

スポンサードサーチ


問題をセットする関数の作成

この関数では、PlayFieldWidgetからマッチ棒の削除やmsDictを空にする、問題の更新などを行います。

先ほどの動作確認では、MatchStickQuizApp内で直接quesListに問題を代入していましたが、これからはこの関数を実行するだけで問題をセットできるようにします。

 

 

コードの提示

問題をセットする関数のソースコードを以下に示します。

import kivy
kivy.require("2.0.0")

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.graphics import Rotate
from kivy.graphics.context_instructions import PushMatrix, PopMatrix
from kivy.storage.jsonstore import JsonStore

import numpy as np
import random

class MatchStickWidget(Widget):
    # 省略

class MatchStickFrameWidget(Widget):
    # 省略

class PlayFieldWidget(FloatLayout):
    def __init__(self, **kwargs):
        # 省略
    def on_size(self, *args):
        # 省略
    def setQA(self, *args):
        for ms in list(self.msDict.keys()):
            self.remove_widget(ms)
        self.msDict = {}
        self.onMoveObj = None
        ans = random.choice(list(self.QADict.keys()))
        self.quesList = random.choice(self.QADict[ans]).split(" ")
        self.ansList = ans.split(" ")
        self.input_ansList = []
        self.drawQuestion()
    def calcPos(self, base_x, base_y, k, *args):
        # 省略
    def drawFrame(self, *args):
        # 省略
    def drawQuestion(self, *args):
        # 省略

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Color(rgb=[1, 1, 1])
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
    def on_size(self, *args):
        self.bg_rect.size = self.size

class MatchStickQuizApp(App):
    def build(self):
        root = RootWidget()
        pfw = PlayFieldWidget()
        pfw.QADict = JsonStore("./matchstickquiz_QA.json")
        pfw.setQA()
        root.add_widget(pfw)
        return root

if __name__ == '__main__':
    MatchStickQuizApp().run()
    pass

 

上記のコードは以下からダウンロードできます。

  

 

コードの解説

10行目の「import文」は、JsonStoreをインポートしています。

JsonStoreは、jsonファイルを辞書型へ変換する関数です。問題と答えをjson形式で保存したためこの関数を使って辞書型に変換します。

 

 

13行目の「import文」は、randomライブラリをインポートしています。問題を選択するさいに、使用するためインポートしています。

 

 

26行目から35行目の「setQA」は、問題をセットする関数です。

 

27行目の「for文」は、msDictのキーの数だけ繰り返します。繰り返し変数は、マッチ棒オブジェクトとなります。

 

28行目の「self.remove_widget(ms)」は、PlayFieldWidgetからマッチ棒オブジェクトのみを削除しています。

 

29行目は、msDictを空にしています。

 

30行目は、onMoveObjにNoneを代入し初期化しています。

 

31行目の「ans」は、QADictのキーからrandom.choiceによって1つだけを取得した答えを代入する変数です。

 

32行目は、ansに対する問題をrandom.choiceによって1つだけ取得し、split関数によって文字列からリスト型へ変換しています。また、その値を代入しています。

 

33行目は、ansにsplit関数を実行し文字列からリスト型へ変換しています。また、その値を代入しています。

 

34行目は、プレイヤーが入力した答えが保持される変数を初期化しています。

 

35行目の「self.drawQuestion()」は、問題を表示しています。

 

 

動作確認

コードを保存したら、コマンドプロンプトを開きファイルを保存したフォルダまで移動します。移動したら、以下のコマンドを入力し実行します。

python matchstickquiz.py

 

ウィンドウを最大化し、以下のように表示されれば動作確認完了です。

  

 

スポンサードサーチ


まとめ

今回は、問題を表示する関数と問題をセットする関数を作成しました。

問題を表示する関数は、ほとんどマッチ棒枠を表示する関数と同じであるため理解しやすかったと思います。

 

次回Part13は、答えを表示する関数と答えをチェックする関数を作成します。

 

 

 

最後までお読みいただきありがとうございます。


スポンサードサーチ