滝の音

滝の音

名こそ流れてなお聞こえけれ

計算プリントを自動生成する その14_2 解析関数

はじめに

前回までに、「3数以上からなる計算式の問題」を作成できるようになりました。
今回はその問題の答えを求める関数を書きます。

解析関数

この関数自体は、前に凍結した「その11」の時に考えていました。
使い道はよくわからないけど便利かもしれないな~と思って。

これが当時に書けていたらもうちょっと頑張れたかもですね。
ただ、これには「Fraction」クラスを用いているので、当時の手持ちでは無理でしたが。

コード

Function Int_Calculation_Analyze(ByVal str As String)
'----------------------
'整数の計算式の答えを求める
'----------------------

'----------------------
'変数の定義
'----------------------
 
 Dim num() As Fraction  '数字を仕分ける変数
 Dim ope() As String    '演算子を仕分ける変数
 Dim i As Integer       '繰り返しの制御変数
 Dim trgt As String     '仕分けのアシスト変数
 Dim stock As String    '仕分けのアシスト変数
 Dim cnt As Integer     '仕分けのアシスト変数
 Dim trgt2 As String    '計算のアシスト変数
 Dim ans As Fraction    '計算のアシスト変数
 
 
Rtrn:
'----------------------
'変数の初期化
'----------------------
 cnt = 0
 stock = ""
 trgt = ""
 trgt2 = ""
 ReDim num(cnt)
 ReDim ope(cnt)
 Set ans = New Fraction
'----------------------
'strをopeとnumに分ける
'----------------------
 For i = 1 To Len(str)
 
    trgt = Mid(str, i, 1)
    Select Case trgt
        Case Is = "+", "-", "×", "÷"
        
            ReDim Preserve num(cnt)
            ReDim Preserve ope(cnt)
            Set num(cnt) = New Fraction
            num(cnt).Con (stock)
            ope(cnt) = trgt

            stock = ""
            cnt = cnt + 1
            
        Case Else
            stock = stock & trgt
    End Select
 Next

 If stock <> "" Then
    ReDim Preserve num(cnt)
    Set num(cnt) = New Fraction
    num(cnt).Con (stock)
    stock = ""
 End If
 
'----------------------
'条件を満たしている場合は終了
'----------------------
 If cnt = 0 Then
    Int_Calculation_Analyze = str
    Exit Function
 End If
 
'----------------------
'計算を行う
'----------------------
 trgt2 = ""
 For i = 0 To UBound(ope)
    Select Case ope(i)
        Case "×"
            trgt2 = num(i).str & ope(i) & num(i + 1).str
            ans.Va = num(i).Va * num(i + 1).Va
            ans.Vb = num(i).Vb * num(i + 1).Vb
            str = Replace(str, trgt2, ans.str, , 1)
            GoTo Rtrn
            
        Case "÷"
            trgt2 = num(i).str & ope(i) & num(i + 1).str
            ans.Va = num(i).Va * num(i + 1).Vb
            ans.Vb = num(i).Vb * num(i + 1).Va
            str = Replace(str, trgt2, ans.str, , 1)
            GoTo Rtrn
    End Select
 Next
 
 For i = 0 To cnt
    Select Case ope(i)
        Case "+"
            trgt2 = num(i).str & ope(i) & num(i + 1).str
            ans.Va = num(i).Va * num(i + 1).Vb + num(i).Vb * num(i + 1).Va
            ans.Vb = num(i).Vb * num(i + 1).Vb
            str = Replace(str, trgt2, ans.str, , 1)
            GoTo Rtrn
            
        Case "-"
            trgt2 = num(i).str & ope(i) & num(i + 1).str
            ans.Va = num(i).Va * num(i + 1).Vb - num(i).Vb * num(i + 1).Va
            ans.Vb = num(i).Vb * num(i + 1).Vb
            str = Replace(str, trgt2, ans.str, , 1)
            GoTo Rtrn
    End Select
 Next
 
'----------------
'予期せぬ処理の場合はSTOP
'----------------
 Stop
 
End Function

正直あまり格好良くない関数です。
格好良い関数が思いつかなかったのでしかたない。
悲しいですが、できることをやっていくだけです。

「それでも良かれと思った道を選ぶ」って言葉を思い出します。
灼眼のシャナというライトノベルで出てくるのですが笑

クラスモジュール「Fraction」

そうそう。 今回のAnalyze関数を動かすために、Fractionにも関数を足しました。

Public Va As Integer    '分子
Public Vb As Integer    '分母

Private Sub Class_Initialize()
 Va = 0
 Vb = 1
End Sub

Property Get str() As String
'--------------------
'Va/Vb
'--------------------

 If Va = 0 Then
    str = "0"
 ElseIf Vb = 1 Then
    str = Va
 Else
    str = Va & "/" & Vb
 End If
End Property

Function Con(str)
'-------------------
'文字式から分子と分母を得る
'-------------------

 Dim trgt As String
 Dim stock As String
 Dim i As Integer
 
 If str = "" Then Exit Function
 
 If InStr(str, "/") = 0 Then
    Va = Val(str)
    Exit Function
 End If
 
 For i = 1 To Len(str)
    trgt = Mid(str, i, 1)
    If trgt = "/" Then
        Va = Val(stock)
        stock = ""
    Else
        stock = stock & trgt
    End If
 Next
 
 If stock = "" Then
    Vb = 1
 Else
    Vb = Val(stock)
 End If
 
End Function
Function Fit()
'---------------------
'約分
'---------------------
 Dim L As Integer   '最大公約数
 L = Application.WorksheetFunction.Gcd(Va, Vb)
 Va = Va / L
 Vb = Vb / L
End Function

ちょっと気持ちの悪いコードになってしまいましたが、今は考えたくないので書き直しは保留。

まとめ

コードは管理不細工ですが。
これで「ランダム作成した問題の答えを求める」ことができます。

次回は「答えから問題を書き換える」について書きます。