滝の音

滝の音

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

計算プリントを自動生成する その12_2 分数の計算

はじめに

前回は分数クラスを作成しました。
今回はそれを使って分数の計算を実装します。

自動でやってみる

いきなり四則の計算を想定して書きます。

クラスモジュール

これは前回書いた通りです。

Fra_Calculation

Function Fra_Calculation(version, level) As String
'----------------------------------
'整数の計算式を生成する
'version=1は足し算
'version=2は引き算
'version=3は掛け算
'version=4は割り算
'----------------------------------

'----------------------------------
'扱う変数の定義
'----------------------------------
 Dim kou() As String  '指定する数値
 Dim ans As String      'strに戻す値
 Dim tmp As String     'numを入れ替えるための変数
'----------------------------------

'kouの値の決定
'----------------------------------
 kou() = Fra_Num_Select(version)

 
'----------------------------------
'計算式を文字列にする
'----------------------------------
 Select Case version
    Case Is = 1
        ans = "a+b=c"
    Case Is = 2
        ans = "a-b=c"
    Case Is = 3
        ans = "a×b=c"
    Case Is = 4
        ans = "a÷b=c"
 End Select
 
 ans = Replace(ans, "a", kou(1))
 ans = Replace(ans, "b", kou(2))
 ans = Replace(ans, "c", kou(3))

'----------------------------------
'文字列を戻す
'----------------------------------
 Fra_Calculation = ans
End Function

これは「Int_Calculation」とほとんどおなじコードです。
「Num_Select」系の関数からの戻り値をString型にしたところが変更点です。

ちなみに「Fra」は「Fraction」の頭三文字です。

Fra _Num_Select

戻り値の型をStringにしたことで少し意味合いが変わりました。
Num_SelectよりもTerm_Makeのほうが近いかもしれませんね。
しばらくは名残でそのままの名前にしておきます。

Function Fra_Num_Select(version) As String()
'------------------------
'変数の定義
'------------------------
 Dim kou(1 To 3) As Fraction    '分数
 Dim swt As Integer
 Dim ans(1 To 3) As String      '戻り値用の変数
 
'------------------------
'kouの値を仮決め
'------------------------
 Set kou(1) = New Fraction
 Set kou(2) = New Fraction
 Set kou(3) = New Fraction
 
 kou(1).Va = Rnd_Num(1, 3)
 kou(1).Vb = Rnd_Num(3, 8)
 kou(2).Va = Rnd_Num(1, 3)
 kou(2).Vb = Rnd_Num(1, 3) * kou(1).Vb
 
'-------------------------
'versionを反映してkou1,2を本決定
'-------------------------

 Select Case version
    Case Is = 1
    
    Case Is = 2
        If kou(1).Va * kou(2).Vb - kou(1).Vb * kou(2).Va < 0 Then
            swt = kou(1).Va
            kou(1).Va = kou(2).Va
            kou(2).Va = swt
            
            swt = kou(1).Vb
            kou(1).Vb = kou(2).Vb
            kou(2).Vb = swt
        End If
        
    Case Is = 3
        swt = kou(2).Va
        kou(2).Va = kou(2).Vb
        kou(2).Vb = swt
        
    Case Is = 4

 End Select
 
'-------------------------
'kou3を決定
'-------------------------
  Select Case version
    Case Is = 1
        kou(3).Va = kou(1).Va * kou(2).Vb + kou(1).Vb * kou(2).Va
        kou(3).Vb = kou(1).Vb * kou(2).Vb
        
    Case Is = 2

        kou(3).Va = kou(1).Va * kou(2).Vb - kou(1).Vb * kou(2).Va
        kou(3).Vb = kou(1).Vb * kou(2).Vb
        
    Case Is = 3
        
        kou(3).Va = kou(1).Va * kou(2).Va
        kou(3).Vb = kou(1).Vb * kou(2).Vb
    
    Case Is = 4
        kou(3).Va = kou(1).Va * kou(2).Vb
        kou(3).Vb = kou(1).Vb * kou(2).Va
        
 End Select
'------------------------------
'kouの約分
'------------------------------
 kou(1).Fit
 kou(2).Fit
 kou(3).Fit
 
'------------------------------
'戻り値を決定
'------------------------------
 ans(1) = kou(1).Str
 ans(2) = kou(2).Str
 ans(3) = kou(3).Str
 
 Fra_Num_Select = ans
 
End Function

こちらは整数の時とはだいぶ違う仕様にしました。
とくに引き算や割り算。
計算前に値を調整するタイプに変えました。

まとめ

これらを組み合わせることでとりあえず分数の四則の計算が実装されました。
難度設定は、正直やっていて頭が痛くなるので保留します。

第12回までやってみてなんとなく気づきました。

あんまり気が乗らないものを義務感で行うとモチベーションが下がって、コードを書くこと自体がおっくうになってしまうことに。

めんどくさいなと感じたものはどんどん保留なり凍結なりして
「最初の願い」を失わいようにしたいなぁと思います。

次回は負の数。
次々回は3数の計算のリベンジ。

こんな流れで行きます。

数学プリントを自動生成する その12_1 分数 クラスモジュールをつくる

はじめに

分数の計算です。
今回はまずクラスモジュールをつくります。

分数の特徴

分数といえば。
1. 分子 2. 分母 3. 表記方法 4. 約分 5. 通分 このあたりが特徴でしょう。

クラスモジュールではこれらのうち1~4を実現させます。
5は関数のほうで

クラスモジュール

名前は「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 Fit()
'---------------------
'約分
'---------------------
 Dim L As Integer   '最大公約数
 L = Application.WorksheetFunction.Gcd(Va, Vb)
 Va = Va / L
 Vb = Vb / L
End Function

分数の特徴とコードの対応は以下の通り。

特徴 コード
分子 Va
分母 Vb
表記方法 Str
約分 Fit

たとえば。
Fraction型の変数「num」について。

コード 意味
num.Va=3 分子が3
num.Vb=8 分母が8
num.Str ”3/8”
num.Fit 約分して分子と分母の数値を更新する

のようになります。

分子や分母の値を使いたいときはVaやVbを、文字列として扱いたいときはFormを使えるという、なかなか便利な仕様です。

まとめ

今回はクラスモジュールの説明に1回分の記事を割きました。
クラスモジュールも、プリント作成においてとても大事なツールです。
次回はこれを使って分数の計算を実装します。

計算プリントを自動生成する その11 整数3つの四則の計算(a+b×c)

はじめに

整数2つの四則の計算と、それを作るうちに生じた課題を前回までにまとめました。
今回は整数3つの四則の計算です。

今回はとりあえず「a+b×c」を実装します。

手順

  1. 整数を3つ選ぶ
  2. a+b×cの答えを求める
  3. 計算式をつくる

手動でやってみる

手順 数字
整数を3つ選ぶ 3,5,7
a+b×cの答えを求める 38
計算式をつくる 3+5×7=38

自動でやってみる

ひながた_Limited

まずは演算子を2つ用意しないといけないので、変数「version」を配列にします。
今回は「a+b×c」に限っているので、関数の語尾に_Limitedをつけます。

Sub ひながた_Limited()

'------------------------------
'0. 扱う変数の定義
'------------------------------
 Dim N As Integer       '問題数を決める変数
 Dim NN As Integer      '扱う数字の個数
 Dim version() As Integer '計算の種類を決める変数
 Dim level As Integer   '難度を決める変数
 Dim i As Integer       '繰り返しの制御変数
 Dim str As String      '計算式の文字列

'------------------------------
'1. 問題数の指定
'------------------------------
 N = 10
 
 For i = 1 To N
    '------------------------------
    '2. 問題を指定して式を求める
    '------------------------------
    NN = 3
    ReDim version(1, NN - 1)
    version(1) = 1
    version(2) = 3
    level = 1
    
    str = Int_Calculation_Limited(NN, version, level)
 
    '------------------------------
    '3. 出力
    '------------------------------
    Call Insert_Equation(20, 30 * i, str)
 Next

End Sub

Int_Calculation_Limited

Function Int_Calculation_Limited(NN, version, level) As String

'----------------------------------
'扱う変数の定義
'----------------------------------

 Dim num() As Integer       '指定する数値
 Dim ans As String          'strに戻す値

'----------------------------------
'numの値の決定
'----------------------------------
 num() = Int_Calculation_Num_Select_Limited(NN)
 
'----------------------------------
'計算式を文字列にする
'----------------------------------
 ans = "num1+num2×num3=num4"
 
 For i = 1 To NN + 1
    ans = Replace(ans, "num" & i, num(i))
 Next
 
'----------------------------------
'文字列を戻す
'----------------------------------
 Int_Calculation_Limited = ans
End Function

一番の特徴は、計算式を文字列にする箇所です。
いままで「a+b=c」だった部分を「num1+num2×num3=num4」にしています。

Int_Calculation_Num_Select_Limited

Function Int_Calculation_Num_Select_Limited(NN) As Integer()

'--------------------------
'変数の定義
'--------------------------
 Dim num() As Integer
 Dim i As Integer
 
 ReDim num(1 To NN + 1)
'--------------------------
'numの決定
'--------------------------

 For i = 1 To NN
    num(i) = Rnd_Num(1, 9)
 Next
 
 num(4) = num(1) + num(2) * num(3)
 
 Int_Calculation_Num_Select_Limited = num

End Function

今回は限定版なのでとりあえず1ケタの数字を3つランダムに選択することにしました。

まとめ

次回以降にLimitedを外していこうと思っていたのですが
ちょっと思ったより難しそうなので「整数3つの四則の計算」はここでいったん凍結します。

これを進めるには少なくとも
「分数の計算」と「負の数の計算」が必要みたいなので
次回以降はそれらに取り組みます。

計算プリントを自動生成する その10 保留のまとめ

はじめに

今回は特にコードは書きません。
今までに保留です~といっていたものをリストアップして
解決できるものは解決します。
保留するものは改めて保留します。

保留のリストアップ

Int_AddSub_Num_Selectが煩雑

これはその4_2で保留した問題です。
特に変数「M」「N」がうっとうしいですね。
これはlevelを細かく設定しすぎたことが原因です。

なのでもう少し難度をシンプルにします。

また、難度の表記ですが。
1_1_2のように書くことにします。
これはnum(1),num(2)が1ケタ、num(3)が2ケタ以下という意味です。

level 内容
1 1_1_1
2 1_1_2
3 2_1_2
4 2_1_3
5 2_2_2
6 2_2_3

これくらいシンプルにします。

Int_MulDiv_Num_Selectのlevel設定が雑

これはその6で保留した問題。
その8でも再度触れています。

こちらも先ほどのAddSubの難度設定を参考にします。
|level|内容| |---|---| |1|1_1_1| |2|1_1_2| |3|2_1_2| |4|2_1_3| |5|2_2_3| |6|2_2_4|

掛け算の場合は桁数の上がり方が足し算より大きくなるので、そこだけ調整。

Int_MulDiv_Num_Selectが煩雑

これもその6で保留した問題。
num(1)とnum(2)の入れ替えを廃止します。
これによって割り算の難度がちょっとおかしくなってしまうので。
161÷7=23と
161÷23=7だと
やっぱり上のほうが簡単に感じますよね。

あとは傾斜をもっとシンプルにします。

傾斜のかけ方が雑

これもまたその6で保留した問題。
これはまだ保留しておきましょう。

引き算用の処理をどの階層の関数で行うか

これはその7_2。
たしか現状では「Int_Calculation」の層で行っているですが
ひとつ下層の「Num_Select」関数に移します。

負の数に対応していない

これもその7_2。
こちらはもう少ししたら1回をかけて記事にします。

まとめ

読むぶんには息抜きの回かもしれませんが
書くのはだいぶ疲れました。

難しいから放置!
としていたところを集めて対策を練ったわけだから当たり前なのですが。

次回は3数による四則の計算を書きます。
そろそろ分数などに移りたいですね。

計算プリントを自動生成する その9 整数の四則の計算

はじめに

その7からしばらく新たな関数を作っていません。
今回もやはり新しい関数は書きません。

そろそろ書きたいですね笑

Int_AddSubとInt_MulDiv

この二つの関数はほとんど機能が似ています。

  1. 数値を下位の関数で決めてくる
  2. 場合によっては数値を入れ替える
  3. 計算式の文字列を作成する

この中に「足し算ならではのこと」や「割り算で起こりうる例外」は含まれません。
そういった専門的なところは「~~_Num_Select」関数で処理しているためです。

これらはちょっとしたベルトコンベアというか。
ようは流すだけの関数です。

なのでこの2つは統合してしまいましょう。

Int_Calculation

「Int_AddSub」や「Int_MulDiv」の作り方と一緒です。

Function Int_Calculation(version, level) As String
'----------------------------------
'整数の計算式を生成する
'version=1は足し算
'version=2は引き算
'version=3は掛け算
'version=4は割り算
'----------------------------------

'----------------------------------
'扱う変数の定義
'----------------------------------
 Dim num() As Integer   '指定する数値
 Dim ans As String      'strに戻す値
 Dim tmp As Integer     'numを入れ替えるための変数
'----------------------------------

'numの値の決定
'----------------------------------
 Select Case version
    Case Is = 1, 2
        num() = Int_AddSub_Num_Select(level)
    Case Is = 3, 4
        num() = Int_MulDiv_Num_Select(level)
 End Select
 
'----------------------------------
'引き算、割り算用の処理
'----------------------------------
 Select Case version
    Case Is = 1, 3
    Case Is = 2, 4
        tmp = num(1)
        num(1) = num(3)
        num(3) = tmp
 End Select
 
'----------------------------------
'計算式を文字列にする
'----------------------------------
 Select Case version
    Case Is = 1
        ans = "a+b=c"
    Case Is = 2
        ans = "a-b=c"
    Case Is = 3
        ans = "a×b=c"
    Case Is = 4
        ans = "a÷b=c"
 End Select
 
 ans = Replace(ans, "a", num(1))
 ans = Replace(ans, "b", num(2))
 ans = Replace(ans, "c", num(3))

'----------------------------------
'文字列を戻す
'----------------------------------
 Int_Calculation = ans
End Function

ちょちょっと条件分岐を足すだけです。

まとめ

これで整数の四則の計算はクリアです。
たとえばversion-Rnd_Num(1,4)とすると
四則の計算がランダムに表れるプリントが作れます。

今回分かったことは。
うまいこと表の面を作ってあげれば、それに対応する裏の面は簡単に引き出せるということ。
骨格の部分は想像以上に使いまわしができるということ。

次回は先に進む前に「今回は保留です」と言っていた箇所をまとめておきましょう。
それらをその場では解決しませんが、どうやったら解決できそうかくらいは考えます。
一段落ついたのでちょっと息抜きの回です。

計算プリントを自動生成する その8 割り算の計算

はじめに

足し算、掛け算、引き算と来てようやく割り算。
割り算の実装の仕方も引き算と同様です。
今回は「Int_Multiplication」から「Int_MulDiv」を一気に作ります。

そんなに言いたいこともないのでサクッとコードを書いて終わりにしましょう。

自動化してみる

ひながたは今回は省略。
前回付け足した「version」変数を使って以下の変数を制御します。

Int_MulDiv

MulDivってなんか人の名前に見えますね。

Function Int_MulDiv(version, level) As String
'----------------------------------
'整数の計算式を生成する
'version=1は掛け算
'version=2は割り算
'----------------------------------

'----------------------------------
'扱う変数の定義
'----------------------------------
 Dim num() As Integer   '指定する数値
 Dim ans As String      'strに戻す値
 Dim tmp As Integer     'numを入れ替えるための変数
'----------------------------------
'numの値の決定
'----------------------------------
 num() = Int_MulDiv_Num_Select(level)
 
'----------------------------------
'割り算用の処理
'----------------------------------
 If version = 2 Then
    tmp = num(1)
    num(1) = num(3)
    num(3) = tmp
 End If
'----------------------------------
'計算式を文字列にする
'----------------------------------
 Select Case version
    Case Is = 1
        ans = "a×b=c"
    Case Is = 2
        ans = "a÷b=c"
 End Select
 
 ans = Replace(ans, "a", num(1))
 ans = Replace(ans, "b", num(2))
 ans = Replace(ans, "c", num(3))

'----------------------------------
'文字列を戻す
'----------------------------------
 Int_MulDiv = ans
End Function

Int_MulDiv_Num_Select

命名法にのっとって「Int_Multiplication_Num_Select」の名前を変えただけです。

まとめ

この統合は概念的にはだいぶ大きい変化な気がするのですが
コードにしてみると全然大したことないですね。
ちょろっと数行足しただけだし。
別に関数を足したわけでもないし。

こちらもAddSubと同様にlevelの反映が適切かどうか疑問ですが
やっぱり保留!

次回はAddSubとMulDivを統合しようと思います。
統合というか仕分けが似ている関数を合併するだけというか。。

計算プリントを自動生成する その7_2 引き算を考える(Int_AddSubの実装)

はじめに

前回「Int_Subtraction」を書きましたが
今回はこれを「Int_Addition」と統合します。

AdditionとSubtracitonの頭3文字をとって「Int_AddSub」関数を!

統合する準備

「Int_AddSub」には作ってほしい計算式が足し算なのか引き算なのか教える必要があります。
なので新たな変数「version」を設けます。
この変数は「level」を足した時と同様に「ひながた」で制御します。

あとは「version」の値と条件分岐でこなします。

自動化してみる

ひながた

Sub ひながた()

'------------------------------
'0. 扱う変数の定義
'------------------------------
 Dim N As Integer       '問題数を決める変数
 Dim i As Integer       '繰り返しの制御変数
 Dim str As String      '計算式の文字列
 Dim version As Integer '計算の種類を決める変数
 Dim level As Integer   '難度を決める変数

'------------------------------
'1. 問題数の指定
'------------------------------
 N = 10
 
 For i = 1 To N
    '------------------------------
    '2. 問題を指定して式を求める
    '------------------------------
    version = 2
    level = 2
    
    str = Int_AddSub(version, level)
 
    '------------------------------
    '3. 出力
    '------------------------------
    Call Insert_Str(20, 30 * i, str)
 Next

End Sub

Int_AddSub

Function Int_AddSub(version, level) As String
'----------------------------------
'整数の計算式を生成する
'version=1は足し算
'version=2は引き算
'----------------------------------

'----------------------------------
'扱う変数の定義
'----------------------------------
 Dim num() As Integer    '指定する数値
 Dim tmp As Integer      'numを入れ替えるための変数
 Dim ans As String       'strに戻す値

'----------------------------------
'numの値の決定
'----------------------------------
 num() = Int_AddSub_Num_Select(level)

'----------------------------------
'引き算用の処理
'----------------------------------
 If version = 2 Then
    tmp = num(1)
    num(1) = num(3)
    num(3) = tmp
 End If
 
'----------------------------------
'計算式を文字列にする
'----------------------------------
 Select Case version
    Case Is = 1
        ans = "a+b=c"
    Case Is = 2
        ans = "a-b=c"
 End Select

 ans = Replace(ans, "a", num(1))
 ans = Replace(ans, "b", num(2))
 ans = Replace(ans, "c", num(3))
 
'----------------------------------
'文字列を戻す
'----------------------------------
 Int_AddSub = ans
End Function

引き算用の処理をこの関数で行うか一つ下の関数で行うか迷いました。
とりあえず保留でこの関数で行っています。

Int_AddSub_Num_Select

これは「Int_Addition_Num_Select」関数と同じなのですが、命名法にのっとって名前だけ変えました。

まとめ

あらためて見返すと「Int_Addition_Num_Select」での難度の反映の仕方がちょっとまどろっこしい気がしますね。

あと、この体制だと3-5=-2のような計算式が出せないことに気づいてしまいました。
さらに言うとnum(1)=-5のようなことも現状ではできませんね。。

この問題はあとで絶対にぶつかりますがとりあえず保留。

次回は割り算の計算を扱います。
とりあえず整数(正確には自然数)の四則の計算を扱えるようにしましょう。