Visual Basic 6.0 初級講座
VB6対応

 

Visual Basic 中学校 > VB6 初級講座 >

第16回 英単語の練習 後編

 

英単語の練習の第2回です。前回の内容を読んでいないと理解しにくい部分があると思います。

さて、今回は前回のプログラムに次のような改良を加えます。

1.問題データとプログラムを分離する。

2.問題をランダムに出題するようにする。

また、最後の完成版をダウンロードできるようにしています。先にダウンロードしてから解説を読むというのも良いでしょう。

 

1.問題データとプログラムを分離する

 

前回はプログラムの中に問題と答えを組み込みました。それでいい場合もあるのでしょうが今回作っている英単語の練習は学年が進むたびに、あるいは定期試験が終わるたびに違う問題を練習したいと思うのが普通でしょう。いつまでも同じ問題では一定以上のレベルアップができません。

問題を変えるにはプログラムをいじって問題を変えればよいのですがもっとうまい方法があります。はじめからプログラムの中に問題を作らなければいいのです。問題は「問題集ファイル」に記録してプログラムからはその問題集を読み込むだけにすると良いでしょう。

このようにプログラムからデータを独立してファイルに記録したいとき、そのファイルの形式は自分で自由に決めることができます。拡張子も自由です。ここでは拡張子が eng である「問題集ファイル」を作ってしましましょう。

問題集ファイルに必要なのは問題と答えです。1問目の問題、1問目の答え、2問目の問題、2問目の答え。3問目の・・・という順番でデータを並べることにしましょう。そうすると前回作った問題は次のようになります。

"基本的な(b)"

"basic"

"視覚の"

"visual"

"番組"

"program"

これをテキストファイルに自分で書きましょう。 " も忘れないでください。また1行ごとに改行もしてください。とりあえずファイル名は"test.eng"として保存します。

拡張子を変更するとダブルクリックしても反応してくれないのですが、もう一度問題を変えたいときはダブルクリックしてでてくるプログラムの一覧から WordPad を選ぶか、また拡張子を変えてtxtにすればOKです。しかし、いちいちこんなことをするのはとても面倒くさいのでこの点は後で改良することにします。

さて、ファイルの中身を読み込む方法はいくつかありますが、今回は Input# メソッドを使います。このメソッドを使ってファイルのデータを1つ読み込んで変数Datumに格納するには次のようにします。

Open "C:\test.eng" For Input As #1

Input #1 , Datum

Close #1

データを1つ読み出すのに3行も必要かと思われたかも知れませんが最初と最後はファイルを開いたり閉じたりする処理ですので、データを読み込む部分はやはり1行です。

Open "C:\test.eng" For Input As #1 はC:\test.engを開けと言う命令です。ファイルを処理するにはまずこの命令が必要です。For Inputは「読み込みのために開く」を言う意味です。書き込みのために開くときはFor Output とします。As #1はファイルの番号です。VBでは一度の複数のファイルを開くことができるので開いたファイルには番号をつけて管理します。以後 #1 という表記があればそれはこのファイルに対する何らかの処理だと言うことになります。

Input #1 , Datum は#1の内容を1つ読み込んでDatumにコピーしろと言う意味です。ファイルの読み込みは必ず先頭からなされます。ですからこの例では先頭のデータを読み込むことになります。2番目のデータを読み込みたいときはこれに続けてもう1度同様の命令を繰り返すことになります。

とにかく、先頭から1つずつ順番に読み込むのが作法です。戻って前のデータを読んだり、いきなり5番目のデータを読んだりすることはこの方法ではできません。

Close #1は#1を閉じるという意味です。使わなくなったファイルは必ず閉じましょう。

では、この知識を応用してtest.engにあるすべてのデータをQuestionとAnswerに読み込みましょう。

Open "C:\test.eng" For Input As #1

Do 

K = K + 1

Input #1 , Question(K)

Input #1 , Answer(K)

Loop Until EOF(1)

Close #1

Do 〜 Loop は繰り返し命令で、この間にある命令は何回も繰り返されます。ただ無限に繰り返してもしょうがないので「ファイルのデータを全部読み込むまで」と指定しています。その部分は Until EOF(1)です。これで「ファイルのデータを全部読み込むまで命令を繰り返せ」と言う意味になります。

一度繰り返すたびにKの値が1ずつ大きくなっていきます。そして問題をQuestion(K)に、答えをAnswer(K)に読み込んでいきます。最初に1問目の問題、1問目の答え、2問目の問題、2問目の答え。3問目の・・・という順番でデータを並べることに決めておいたのでこの方法で正しくデータを読みとることができます。

これで、問題データとプログラムの分離は完了です。従来のLoadProblemプロシージャを上の物に差し替えましょう。1ついいわすれましたが、問題集ファイルtest.engはこの例ではCドライブに直接置かなければならないことになっています。それは嫌なので、プログラムと同じフォルダに置かなければ行けないように変更しましょう。そのため1行目は次のように変更されます。


Open App.Path & "\test.eng" For Input As #1
 

以上をふまえた全プログラムは次のようになります。

Dim Answer(100) As String 
Dim Question(100) As String
Dim QCount As Integer
Private Sub SetProblem()

QCount = QCount + 1

lblJapan.Caption = Question(QCount)

End Sub

Private Sub Form_Load()

LoadProblem    '問題を読み込む

SetProblem        '最初の問題を出題する

End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)

If KeyAscii = vbKeyReturn Then cmdAnswer_Click

End Sub

Private Sub cmdAnswer_Click()

Cls        '前に書いた○や×を消す

If txtAnswer.Text = Answer(QCount) Then

Circle (ScaleWidth \ 2 , ScaleHeight \ 2) , ScaleHeight \ 2 , RGB(255,0,0)

Else

Line ( 0 , 0 ) - (ScaleWidth , ScaleHeight) , RGB(0,0,255)

Line ( 0 , ScaleHeight) - (ScaleWidth , 0) , RGB(0,0,255)

End If

txtAnswer.Text = ""

SetProblem

End Sub

Private Sub LoadProblem()

Dim K As Integer

Open App.Path & "\test.eng" For Input As #1

Do 

K = K + 1

Input #1 , Question(K)

Input #1 , Answer(K)

Loop Until EOF(1)

Close #1

End Sub

 

2.問題をランダムに出題するようにする

 

問題をランダムに出題するようにする前に問題が全部で何問あるのか把握します。幸い先ほど作ったLoadProblemプロシージャに「ファイルの内容を全部読み込むまで」という部分があったので、このとき問題数を数えていた変数Kの値を記録しておけばよいでしょう。この値を記録するために新たな変数AllQuestionsを設定します。

さて、問題は読み込んだ順に1,2,3,・・・ときれいに並んでいるはずです。この番号は配列で管理されています。配列とは変数の後ろにかっこ付きでくっついている数字でQuestion(1),Question(2)のようなものをいうのでした。

この数字のところをごちゃごちゃに入れ替えればランダムな順番で問題が並ぶことになります。

ここから先はちょっととんちっぽくて頭を使うことが苦手な人にはわかりにくいと思いますので気をつけて読んでください。

順番をでたらめに入れ替える手順は次のようになります。

手順1.K=1をする。

手順2.1〜AllQuestions(全問題数)の範囲で適当な数字を一つ選ぶ。この数字をMとする。

手順3.K問目の問題・答えとM問目の問題・答えを入れ替える。

手順4.もしK=AllQuestionsならここで終了。

手順5.Kに1をたして 手順2 に戻る。

以上の作業をプログラムで実現するにはどうしたらよいでしょうか?簡単なのは手順1、手順4、手順5です。この3つの手順はVBでは Forループにまとめることができます。具体的には次のようになります。

For K = 1 To AllQuestions

Next K

後は手順2と手順3です。かんたんな手順3から説明しましょう。K問目の問題と答えはQuestion(K)とAnswer(K)です。M問目の問題と答えもKをMに変えるだけで同じです。そうするとこの2つを入れ替えるには次のようにすればよいことが分かります。

Dummy = Question(K)

Question(K) = Question(M)

Question(M) = Dummy

途中でダミーの変数を仲介させるわけですね。この例では問題だけなので答えも同様の方法で入れ替えてください。

さて、手順2 「1〜AllQuestions(全問題数)の範囲で適当な数字を一つ選ぶ。この数字をMとする。」ですが、難しいのは 適当な数字を一つ選ぶ をいう部分ではないですか?だいたいコンピュータには「適当」なんて言葉の意味は理解できないのです。一応適当に選んでいるように見せかける Rnd関数 と言う物があります。この関数は 0〜1の間の適当な小数を返す物です。これを使って1〜AllQuestions(全問題数)の範囲で適当な数字を得るには次のようになります。


M = Fix(Rnd * AllQuestions) + 1
 

しかし、これはあくまで「適当に選んでいるように見える」だけで本当は適当じゃありません。その証拠に1回目は適当に見えても、2回目に同じことをやらせると1回目と同様の数ばかり選んでしまいます。つまり結局毎回同じなのです。そこでなぞのキーワードRandomizeの出番です。Rndを呼び出す直前にRandomizeを呼び出すと本当に適当に選んでいるような効果を出すことできます。毎回違う数字が選ばれます。

以上の手順をまとめるとあたらしいLoadProblemプロシージャは次のようになります。

Private Sub LoadProblem()

Dim K As Integer
Dim M As Integer
Dim Dummy As String

Open App.Path & "\test.eng" For Input As #1

Do 

K = K + 1
Input #1 , Question(K)
Input #1 , Answer(K)

Loop Until EOF(1)

Close #1

AllQuestions = K 

For K = 1 To AllQuestions

Randomize

M = Fix (Rnd * AllQuestions) + 1

Dummy = Question(K)
Question(K) = Question(M)
Question(M) = Dummy

Next K

End Sub

これで外部のファイルから問題を読み込んでランダムに出題することが可能になりました。

 

3.問題を能率的に作る

 

プログラムは完成しましたが、問題を作るのが面倒くさいと言う点はあいかわらず残ってしまっています。本来はこの点もしっかり解説すべきなのでしょうが私のパワーと時間の関係で割愛させていただきます。

しかし完全な割愛はしません。このページの最後に簡単に問題を作るサンプルプログラムをおいておきます。コメントなどもつけて多少読みやすくしてありますのでダウンロードしてみてください。

 

4.最後に

 

実は今回のプログラムは英単語の練習以外にも使い道がありそうです。この手の単純なプログラムは単純すぎて売っていないようですが勉強にはかなり役に立つと思っています。どうぞ活用してみてください。

 

5.サンプルのダウンロード

 

ダウンロード版はここで解説している物よりも少しばかり機能を追加しています。また、コメントもたくさんついていますので参考になることと思います。

サンプルのソースコードはVB6(SP3)で作成されています。VB5以前でこれらのファイルを開けないようなら、frmの拡張子をtxtに変更してテキストとして開いてみてください。また、実行ファイルはソースコードを見られない状態でもプログラムとして使用することはできます。ただし、そのためにはVB6ランタイムが必要です。VB6ランタイムを同時に配布すると容量が大きくなるのでここでは配布しません。

VB6ランタイムが必要な人はインターネット上にあるダウンロードサイトから落としてください。

ダウンロード1    英単語の練習 ソースコードと実行ファイル

ダウンロード2    問題作成 ソースコードと実行ファイル

どちらのファイルもLHA形式(拡張子はlzh)で圧縮されています。