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

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

今回は、答えを表示する関数と答えをチェックする関数を作成します。これらの関数は、後々ボタンと連動させて処理させる関数となります。

 

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

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

 

 

 

スポンサードサーチ


答えを表示する関数

この関数では、ansListで保持している答えにマッチ棒を動かすということを行います。

 

パズルゲームを遊んでいるときに、答えを見たくなったことはありませんか?

この関数はプレイヤーが答えを見たくなった時に実行される関数です。

 

 

コードの提示

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

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):
        # 省略
    def calcPos(self, base_x, base_y, k, *args):
        # 省略
    def drawFrame(self, *args):
        # 省略
    def drawQuestion(self, *args):
        # 省略
    def drawAnswer(self, *args):
        tempmsList = list(self.msDict.keys())
        c = 0       # index of tempmsList
        for idx, k in enumerate(self.ansList):
            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.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.QADict = JsonStore("./matchstickquiz_QA.json")
        pfw.setQA()
        root.add_widget(pfw)
        root.bind(on_touch_down=pfw.drawAnswer)
        return root

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

  

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

 

 

コードの解説

35行目から45行目の「drawAnswer関数」は、答えを表示する関数です。

 

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

 

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

 

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

 

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

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

 

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

 

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

 

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

 

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

 

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

 

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

 

 

動作確認

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

python matchstickquiz.py

 

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

 

 

スポンサードサーチ


答えをチェックする関数

この関数は、簡単に言うと答え合わせを行う関数です。

プレイヤーが入力した答えと用意されている答えが同じであるかどうかを判定する関数となります。そのため返される値はTrueまたはFalseです。

 

具体的な処理としては、表示されているマッチ棒の座標を読み取り「x + y = z」のような式を生成します。これがプレイヤーが入力した答えとなります。

その後、プレイヤーが入力した値と用意されている答えと比較を行います。

  

 

コードの提示

答えをチェックする関数のソースコードを以下に示します。

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):
        # 省略
    def calcPos(self, base_x, base_y, k, *args):
        # 省略
    def drawFrame(self, *args):
        # 省略
    def drawQuestion(self, *args):
        # 省略
    def drawAnswer(self, *args):
        # 省略
    def checkAnswerFML(self, *args):
        posTupleList = sorted([ms.pos for ms in list(self.msDict.keys())])
        self.input_ansList = []
        for idx, k in enumerate(self.ansList):
            pos_x_min = self.base_x+idx*(self.ms_w+self.ms_h+self.ms_w)
            pos_x_max = self.base_x+(idx+1)*(self.ms_w+self.ms_h+self.ms_w)
            posList = [t for t in posTupleList if(pos_x_min <= t[0] and t[0] < pos_x_max)]
            lng_posList = len(posList)  # マッチ棒が何本使われているか数える
            if(lng_posList == 1 and posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, "-")]):
                self.input_ansList.append("-")
            elif(lng_posList == 2):
                for i in ["1", "+", "="]:
                    if(posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, i)]):
                        self.input_ansList.append(i)
            elif(lng_posList == 4):
                for i in ["4", "7"]:
                    if(posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, i)]):
                        self.input_ansList.append(i)
            elif(lng_posList == 5):
                for i in ["2", "3", "5"]:
                    if(posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, i)]):
                        self.input_ansList.append(i)
            elif(lng_posList == 6):
                for i in ["0", "6", "9"]:
                    if(posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, i)]):
                        self.input_ansList.append(i)
            elif(lng_posList == 7 and posList == [[t[0], t[1]] for t in self.calcPos(pos_x_min, self.base_y, "8")]):
                self.input_ansList.append("8")
        if(self.input_ansList == self.ansList):
            return True
        return False

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)
        root.bind(on_touch_down=pfw.drawAnswer)
        return root

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

  

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

 

 

コードの解説

36行目から66行目の「checkAnswerFML関数」は、答えをチェックする関数です。

 

37行目の「posTupleList」は、表示されているマッチ棒の座標をx座標について昇順に並び替えた値を代入する変数です。

 

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

 

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

 

40行目の「pos_x_min」と41行目の「pos_x_max」は、それぞれ1つの数字または記号における最小のx座標、最大のx座標を計算し代入する変数です。

 

42行目の「posList」は、pos_x_mini以上pox_x_max未満の座標のみを代入する変数です。

 

43行目の「lng_posList」は、posListに含まれる数を代入する変数です。これを数えることである程度の数字または記号の予測を行うことができます。

 

 

44行目の「if文」は、「lng_posListが1であり、かつposListに代入されている座標が「ー(マイナス)」と同じ座標であるか」を判別する条件式です。Trueであれば、45行目を実行します。

 

45行目は、input_ansListに「ー(マイナス)」を追加しています。

 

 

46行目の「elif文」は、「lng_posListが2であるか」を判別する条件式です。使われているマッチ棒が2つであるということは1か「+」か「=」であるということが分かります。Trueであれば、47行目から49行目を実行します。

 

47行目の「for文」は、マッチ棒2つで表現される数字または記号の種類だけ繰り返しています。

 

48行目の「if文」は、「posListに代入されている座標がcalcPosによって計算した座標と同じであるか」を判別する条件式です。Trueであれば49行目を実行します。

 

49行目は、条件にあった数字または記号をinput_ansListに追加しています。

  

 

50行目の「elif文」は、「lng_posListが4であるか」を判別する条件式です。使われているマッチ棒が4つであるということは4か7であるということが分かります。Trueであれば、51行目から53行目を実行します。

 

51行目の「for文」は、マッチ棒4つで表現される数字または記号の種類だけ繰り返しています。

 

52行目の「if文」は、「posListに代入されている座標がcalcPosによって計算した座標と同じであるか」を判別する条件式です。Trueであれば53行目を実行します。

 

53行目は、条件にあった数字または記号をinput_ansListに追加しています。

 

 

54行目の「elif文」は、「lng_posListが5であるか」を判別する条件式です。使われているマッチ棒が5つであるということは2か3か5であるということが分かります。Trueであれば、55行目から57行目を実行します。

 

55行目の「for文」は、マッチ棒5つで表現される数字の種類だけ繰り返しています。

 

56行目の「if文」は、「posListに代入されている座標がcalcPosによって計算した座標と同じであるか」を判別する条件式です。Trueであれば57行目を実行します。

 

57行目は、条件にあった数字をinput_ansListに追加しています。

  

 

58行目の「elif文」は、「lng_posListが6であるか」を判別する条件式です。使われているマッチ棒が6つであるということは0か6か9であるということが分かります。Trueであれば、59行目から61行目を実行します。

 

59行目の「for文」は、マッチ棒6つで表現される数字の種類だけ繰り返しています。

 

60行目の「if文」は、「posListに代入されている座標がcalcPosによって計算した座標と同じであるか」を判別する条件式です。Trueであれば61行目を実行します。

 

61行目は、条件にあった数字をinput_ansListに追加しています。

  

 

62行目の「elif文」は、「lng_posListが7であり、かつposListに代入されている座標が8と同じ座標であるか」を判別する条件式です。Trueであれば、63行目を実行します。

 

63行目は、input_ansListに8を追加しています。

  

64行目の「if文」は、プレイヤーが入力した答えと用意されている答えが同じであるかを判別する条件式です。Tureであれば65行目を実行します。

 

65行目の「return文」は、Trueを返しています。

 

66行目の「return文」は、Falseを返しています。

 

 

動作確認

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

python matchstickquiz.py

 

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

before drawAnswer :  False
after drawAnswer :  True

  

 

スポンサードサーチ


まとめ

今回は、答えを表示する関数と答えをチェックする関数を作成しました。これらの関数は、後々ボタンと連動させて処理させる関数となります。

 

次回Part14では、マッチ棒を動かす関数とマッチ棒を1本しか動かせないようにする関数を作成します。

 

 

 

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


スポンサードサーチ