滝の音

滝の音

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

計算プリントを自動生成する その6 いろいろな掛け算

はじめに

今回はいろいろな掛け算を実装します。
今回は簡単かなーと思っていたのですが、いざやってみると思いがけない問題が。。

難度の設定

まずは難度を設定します。
どうせ次に変数levelと対応をとるので、初めからその形式で。

level 内容
1 九九の掛け算
2 1ケタ×2ケタ
3 2ケタ×2ケタ、答えが百の位まで
4 2ケタ×2ケタ、答えが千の位まで
5 2ケタ×2ケタ、制約なし

んー。
もしかしたらもっと良い難度設定があるかもしれません。

自動化してみる

傾斜のかけ方

前回の九九の回に傾斜を掛けました。
その時はnumに1が出てきた場合はもう一度数字を選びなおして
出現頻度を偏らせました。

この偏らせ方がlevelによってそれぞれ異なることが作っているうちにわかりました。

たとえば2ケタの数字で10,20,30などが出てくると
これって実質1ケタの掛け算と一緒になってしまいます。

前回は「Int_Multiplication」関数で傾斜を実装していましたが
今回はその一つ下の層の「Int_Multiplication_Num_Select」関数に移します。
傾斜を新しい関数で実装しようかとも考えましたが、傾斜と数値の選択は密接な関係があるので同じ関数内で書くことにしました。

「Int_Multiplication_Num_Select」

まずは前回書いた内容で、この関数内に傾斜を設けてみます。

Function Int_Multiplication_Num_Select(level) As Integer()
'-------------------
'変数の定義
'-------------------
 Dim num() As Integer   '計算式に入れる数値
 Dim N() As Integer     'num1を作るための変数
 Dim M() As Integer     'num2を作るための変数
 Dim i As Integer       '繰り返しの制御変数
Dim flag As Boolean    '傾斜のための変数
'-------------------
'numの数を決定
'-------------------
 ReDim num(1 To 3)

'-------------------
'傾斜の準備
'-------------------
 flag = False
 
ReSelect:
 
'---------------------
'num1,2の値の決定
'---------------------
 num(1) = Rnd_Num(1, 9)
 num(2) = Rnd_Num(1, 9)

'---------------------
'傾斜の設置
'---------------------

 If flag = False Then
    If num(1) = 1 Or num(2) = 1 Then
        flag = True
        GoTo ReSelect
    End If
 End If
 
'---------------------
'num3の値の決定
'---------------------
 num(3) = num(1) * num(2)
 
 Int_Multiplication_Num_Select = num
 
End Function

FlagとReSelectの部分で一度だけ繰り返しを行っています。

続いて先ほど決めたlevelを反映さえます。

Function Int_Multiplication_Num_Select(level) As Integer()
'-------------------
'変数の定義
'-------------------
 Dim num() As Integer   '計算式に入れる数値
 Dim N() As Integer     'num1を作るための変数
 Dim M() As Integer     'num2を作るための変数
 Dim i As Integer       '繰り返しの制御変数
 Dim flag As Boolean    '傾斜のための変数
 Dim adj As Integer     '数字選択補助の変数
'-------------------
'numの数を決定
'-------------------
 ReDim num(1 To 3)

'-------------------
'傾斜の準備
'-------------------
 flag = False
 
ReSelect:
 
'---------------------
'numの値の決定
'---------------------
 Select Case level
    Case Is = 1             '1_1
        num(1) = Rnd_Num(1, 9)
        num(2) = Rnd_Num(1, 9)
    Case Is = 2             '2_1
        num(1) = Rnd_Num(10, 99)
        num(2) = Rnd_Num(1, 9)
    Case Is = 3             '2_2百の位まで
        num(1) = Rnd_Num(10, 99)
        adj = 999 \ num(1)
        num(2) = Rnd_Num(1, adj)
    Case Is = 4             '2_2千の位まで
        num(1) = Rnd_Num(10, 99)
        adj = 999 \ num(1)
        num(2) = Rnd_Num(adj + 1, 99)
    Case Is = 5             '2_2制約なし
        num(1) = Rnd_Num(1, 99)
        num(2) = Rnd_Num(1, 99)
 End Select


'---------------------
'傾斜の設置
'---------------------

 If flag = False Then
    flag = True
    
    Select Case level
        Case Is = 1, 2
            If num(1) = 1 Or num(2) = 1 Then GoTo ReSelect
        Case Is = 3, 4, 5
            If num(1) Mod 10 = 0 Or num(2) Mod 10 = 0 Then GoTo ReSelect
    End Select
 End If
 
'---------------------
'numの入れ替え
'---------------------
 If Rnd() < 0.5 Then
    tmp = num(1)
    num(1) = num(2)
    num(2) = tmp
 End If
 
'---------------------
'num3の値の決定
'---------------------
 num(3) = num(1) * num(2)
 
 Int_Multiplication_Num_Select = num
 
End Function

んー。ちょっとコードがだらだらしてますかね。
Numの入れ替えという機能を追加しました。
たまにnum(1)とnum(2)を入れ替えることで問題の見た目の偏りを和らげています。

まとめ

傾斜の設定が意外と難しいな、という回でした。

前回は気づきませんでしたが、傾斜の設定のやり方で問題の難度を調節できそうですね。
たとえば傾斜と乱数を組み合わせることで「どの程度の割合でReSelectをするか」を決めることができます。

ここまで考え始めると疲れちゃうので今は保留しますが。。