楽しいプログラミング
1999年12月4日
● はじめに
ものを作る楽しみは中学生も大人も同じくもっています。例えば紙飛行機のようにできるだけ遠くに飛ばしたい、できるだけ高く飛ばしたい、というように飛行機を作るときにさまざまな工夫を凝らすことに楽しみを感じます。プログラムもある目的があって、それを実現するために、さまざまな工夫を凝らしてみるところに同じ「作ること」の楽しみが生まれます。今回の勉強では「作るもの」の目的をはっきりせながら、何を入力して、どんな処理をして、何を出力するのか、を学びながらプログラミング(プログラムを作ること)を勉強したいと思います。
●プログラミング言語について
世の中にはたくさんのプログラミング言語が存在しますが、今回はフリーでインターネットからダウンロードできるJIS規格のBASICを採用しました。その理由は
1.フリーで無料で手に入ること
2.BASIC言語は初心者にうけいれやすいこと(昔、使ったことがある人は多い)
3.プログラムサイズが小さく、また、インストールが容易なこと
4.Winodws95,98、NTで動作すること
今回はインターネット上のフリーソフトウェアから「(仮称)十進BASIC
for Windows95」をダウンロードしました。
http://www.vector.co.jp/soft/win95/prog/se039185.html
このプログラムの使用およびこのホームページでのリンクに関して白石和夫先生の快い承諾に感謝いたします。
● BASIC起動のしかたと使い方。
ダウンロードした後、解凍してしてください。「Basicw32」のフォルダに必要な全てのファイルが入っています。詳細なマニュアルは「Tutorial」フォルダの中の「Tutorial.pdf」を参照してください。
Basicの起動は下に示したアイコンをダブルクリックします。
下のようなBASICのウィンドウが現れます。このウィンドウ内にプログラムを書きこみます。
良く使う機能を説明します。
プログラムファイルを開くときます。
プログラムを保存します。
プログラム実行します。
プログラムをステップ実行します。プログラムの実行状態を見ながら実行できます。
プログラムを停止します。
ヘルプファイルを開きます。プログラムの文法などを調べるときに使用します。一度、一通り目を通すことをお勧めします。
● プログラムのコツ
プログラムはコンピュータに仕事をさせるための命令の集まりです。したがって、命令がはっきりしていないとコンピュータは正しく結果を返してくれません。
そこで、プログラムする前に目的をはっきりさせ、以下の点にもはっきりさせる必要があります。
1.何を入力するのか
2.入力した値でどんな処理をするのか
3.処理した結果は何を出力するのか
以上の3点が重要です。
● プログミング(プログラムを作ること)してみよう
1. おこづかいはいくらになるのかな?
「2000年1月1日に1円もらい、2日に2円もらい、毎日1円づつ増やしておこづかいもらう方法を考えました。」さて、このとき、2000年12月31日にはいくら貯まっているのでしょうか?
このプログラムの目的と入力、処理、出力は次のようになります。
目的 :1月1日から12月31日までの合計金額を求める。
入力 :お小遣いをもらい続ける日数。ここでは366日(2000年はうるう年)
処理 :1から日数分加える
出力 :合計値
プログラム(各行の前についている行番号「10、20、30、…」は入力する必要はないよ、また「!」と書いてある以降の文は注釈文なので入力する必要はないよ。)
10 input a !
変数aに合計する日数を入力します。
20 LET sum=0 !
sumは合計を求める変数。0を代入して初期化しています。
30 for i=1 to a
40 LET sum=sum+i !
変数sumにiに入っている値を加えて新たにsumの値にしています。
50 next i
60 print "合計金額:",sum ! 合計金額のsumを表示します。
70 end
さて、プログラムを実行してみましょう。ちょっと、実行する前に合計金額がいくらになるか予測してみましょう。
それでは、実行ボタンをクリックしてプログラム実行してください。
下のウェインドウが開いて、入力が求められます。2000年の1年間の日数、「366」を入力しして「OK」ボタンをクリックします。
計算結果が表示されます。君の予測した値より多かったかな?それとも少なかったかな?
非常に単純なプログラムです。君がコンピュータに命令して実行した「記念すべきプログラム」です。実は私も20数年前にはじめて作ったプログラムがこのプログラムです。すべてはこのプログラムから始まっています。
解説
変数(このプログラムではa、sum、i)は値を入れる箱のようなものです。変数と変数を足したり、引いたり、掛けたり、割ったりして新たな変数に入れたり、40行のように同じ変数に結果を入れて、値を入れ替えることもできちゃいます。
プログラムの実行は行番号の最初から順番に実行されていきます。しかし、このプログラムでは1日から366日目までを繰り返し処理する必要があるので、「for〜next構文」(30行、50行)が使われています。変数iの値を1から変数aの値まで1つずつ増やしていき、50行のnext iまで繰り返します。変数iの値が変数aの値に等しくなったときに、この「for〜next構文」を出ます。この繰り返しの間、変数iが1づつ増えていき、前の値(変数sum)に加えられた結果がまた、変数sumに代入されて合計金額が増えていきます。
値の入力には「input文」を使います。10行目のinput文は変数aにキーボードから入力された値が入ります。
値の出力には「print文」を使います。60行目のprint文は「合計金額:」と表示した後に、合計金額を求めた変数sumの中の値が表示されます。ここで「合計金額:」を囲っているダブルクォテーション「”」は半角です。注意しましょう。この「”」の間に囲まれた中の文字は半角でも、全角でもコンピュータ画面に表示することができます。
2. 体の発育状況をローレル指数を求めて調べてみよう
ローレル指数は身長と体重から求めます。式は体重(kg)を身長(cm)の3乗したもので割、10000000を掛けて求めます。
ローレル指数=体重/身長3 ×1000000
求めたローレル指数値から、発育の判定を下の4つに分類しました。(作者の「おもい」が入っています。)
100未満 「好き嫌いなくなんでも食べよう。」
100以上、109未満 「好き嫌いをなくそう」
109以上、140未満 「問題なし」
140以上 「もっと運動しよう」
目的 :体の発育状況を調べる。
入力 :身長(cm)と体重(kg)
処理 :ローレル指数の計算式
結果 :4つの分類によりそれぞれのコメントを出力する。
プログラム(行番号と「!」の付いた行は入力しなくてもいいよ)
100 ! ローレル指数
110
120 input prompt "体重を入力してください(kg)":w ! 変数wに体重が入る
130
140 input prompt "身長を入力してください(cm)":h ! 変数hに身長が入る
150
160 LET r=w/(h^3)*1E7 !ローレル指数の計算をして、結果は変数rに入る
170
180 print "ローレル指数は";r !ローレル指数を表示します。
190
200 if r<100 then !100未満かどうか判定します。
210 print
"好き嫌いなくなんでも食べよう。" !100未満のとき、表示します。
220 end if
230
240 if r>=100 and r<109 then !100以上、109未満か判定します。
250 print
"好き嫌いをなくそう" !判定の該当したとき、表示します。
260 end if
270
280 if r>=109 and r<140 then
290 print
"問題なしだね"
300 end if
310
320 if r>=140 then
330 print
"もっと運動しよう"
340 end if
350
360 END
入力し終わったら、実行ボタンをクリックして実行してみましょう。
下のようなウィンドウが開いて、「体重を入力してください(Kg)」と促されます。
体重を入力すると、今度は身長を入力します。
体重を40Kg、身長を150cmと入力すると、下のように計算されたローレル指数と判定結果「問題なしだね」と表示されます。もちろん問題があれば異なった表示をします。
君の身長と体重ではどういう判定になったかな?
解説
今回、入力するウィンドウに「体重を入力してください(Kg)」と表示されました。これは入力の「input文」に「input prompt文」を使用したので、ダブルクォテーション「”」に囲まれた部分が入力ウィンドウに表示されました。正しく入力してもらうために便利な「input prompt文」です。
このプログラムでは2つの入力値(身長と体重)から処理した結果(ローレル指数)をもとに、4つの判定を行っています。4つのどの判定を使用するかは条件判断(「if 〜 then」構文)を用いています。
「if」と「then」の間に条件式が書き書きこまれます。200行では条件式に「r<100」と書かれています。つまり、「ローレル指数rが100未満であれば」という意味です。この条件を満たしていると、「if」行と「end if」行で囲まれた次の行(210行)の判定結(「print文」)を実行します。
「if」行と「end if」行の間には何行でもプログラムを書きこむことができるよ。
「if〜then」構文は条件によりプログラムを切りかえることができます。例のように4つの出力のどれを出力するかを決めています。プログラムの基本なので、使い方をマスターしようね。
3. 暗号文をつくる。
誰にもわからない秘密の文書を作成して、友人に大事な用件を送ろう。そんな秘密の文書=暗号文をつくろう。
さて、暗号文書作る前に、コンピュータの中で文字はどのように扱われているのだろうか。下のプログラムを入力して調べてみよう。
100 do
110 print
"入力(AからZ、0から9)"
120 input
moji$
130 print
moji$;"-->";ord(moji$)
140 loop
150 END
さて、実行してみましょう。
文字入力を求めるウィンドウが現れます。ここで、「a」と入力してみましょう。
すると、aはコンピュータの内部では「97」という数字に置き換えられます。
好きな英数字を入力してみましょう。
解説
moji$は文字変数を表しています。文字変数は変数名の後に「$」が付きます。いままでの変数は数字を入れるための数字変数でした。このようにコンピュータに変数に入れる値が「数字」なのか「文字」なのか明示的に変数を定義することができます。
コンピュータの中では、文字は数字で表されています。英数文字は1バイトというコンピュータの扱う情報単位で管理しています。文字が数字であることを利用して、暗号化しようというのが目的です。
Ord関数は文字をコンピュータ内部で使用している数字(文字コードと呼ぶ)に変換します。ですから、入力した文字がコンピュータ内部どの数字に割当てられているか知ることができます。
このプログラムでは繰り返しに「do〜loop」文を使用しています。doとloopに囲まれたプログラムを無限に繰り返し実行します。
さて、暗号文作成および暗号解読作成プログラムを作成してみましょう。
目的 :暗号文の作成
入力 :暗号キー(数字で1桁とします)
暗号化したい文書
処理 :入力した文書の各文字に暗号キーを加えて暗号文を作成します。
最大文字コード超えた場合、小さい文字コードに割り振ります。
出力 :暗号文
復号化プログラムの作成
目的 :暗号文を元の文に戻す。
入力 :復号キー(数字。暗号キーといっしょでないともとに戻りません)
暗号文
処理 :暗号文の各文字から復号キーを引いて、元の文章に戻します。
最小文字コードを超えた場合、大きな文字コードに割り振ります。
出力 :復号文(元の文書)
プログラム
100 ! 暗号文の作成
110
120 input prompt "暗号キー":akey !1桁の数字(1〜9)
130 input prompt "もとの文章":org$
140
150 !暗号化
160 for i=1 to len(org$)
170 LET a=ord(org$(i:i))+akey ! 暗号キーを加える
180 if
a>=127 then
!最大文字コードを超えたとき
190 LET a=a-127+32
!小さい文字コードに割り振る
200 LET cd$(i:i)=chr$(a) !文字コードを文字に置き換える
210 else
220 LET cd$(i:i)=chr$(a)
230 end if
240 next i
250
260 print "暗号文章 ";cd$
270 pause
280
290
300 !復号化
310 input prompt "復号キー ":akey
320
330 for i=1 to len(cd$)
340 LET a=ord(cd$(i:i))-akey !暗号キーを引く
350 if
a<=32 then
!最小文字コードを超えたとき
360 LET a=a+127-32 !大きい文字コードにする。
370 LET enc$(i:i)=chr$(a) !文字コードを文字に置き換える
380 else
390 LET enc$(i:i)=chr$(a)
400 end if
410 next i
420
430 print "解読文章 ";enc$
440
450 END
さて、実行してみましょう。
暗号キーを入力します。数字(1から9)を入力してください。
つぎに、暗号化する文章を入れます。
すると、暗号化された文章が下のように表示されます。
暗号文章のあとに意味不明の文字表示され、暗号文が作成されたのが確認できます。
PauseのOKボタンをクリックして、次に進みます。
暗号文を元に戻すための、復号キーの入力を求められます。先ほど入力した暗号キーと同じ数字を入力します。
下のように、暗号文が解読されて元に戻ったのがわかります。
暗号キーや符号キーをいろいろ変えてみて、暗号文の変かを調べてみましょう。
解説
最も原始的な暗号化の方法を紹介しました。現在、広く使われている暗号の元祖です。
さて、プログラムは1文字ずつの処理を行うために160行で「for〜next構文」を使用しています。入力した文書(変数org$)に何文字あるか調べるのにlen()関数を用いています。この関数の返す値分(文字数分)「for〜next構文」が繰り返されます。
cd$(i:i)は文字変数cd$の中からI番目の文字を1文字取り出します。170行で1文字を数字に変換したものに暗号キー(akey)を加えて暗号化しています。
a=a-127+32は変数aが126をいくつ超えたか計算し、最小文字コード(32)からその分を加えて新しい文字を割当てています。したがって、最小文字コード32から最大文字コード126を循環するように割り振っています。
210行で「else」という新しい言葉が出てきています。前に習った「if 〜 then構文」で1つの条件に対して「条件に当てはまる場合」と「それ以外」というときに使います。
if 条件 then
条件に当てはまるときの処理
else
条件に当てはまらないときの処理
end if
というようになります。
文字を数字に変えるのにord()関数を使用しましたが、数字を文字に変換するのにchr$()関数を使用してもとの文字に変換しています。
復号する時は暗号化の逆を行っています。
4. 円周率πを求める
方法をピタゴラスの定理から円周率πを求めてみましょう。ここでは同時に線を描く「グラフィックス機能」と「コンピュータの計算精度」について学びましょう。
方法は円の4分の1だけ取り出して考えます。いま円の半径を100としたとき、x座標上で点P、とその垂線が円と交わる点Qと原点(0,0)を結ぶ三角形を考えました。
この点Pをxが0から99まで移動させながら、長さPQを求めて加えれば円の面積の1/4になるだろうと考えました.こうして求めた円の面積Sからπを下の式から求めました。
Sは円の面積の1/4なので、4倍すると正しい円の面積になるので、(1)式のようになります。
S*4=π*半径*半径 ……(1)
(1)式をπについて解くと(2)式になります。
π=S*4/(半径*半径) ……(2)
また、PQの長さはピタゴラスの定理から次のようにして求めました
半径×半径=OP×OP+PQ×PQ ……(3)
PQ=平方根(半径×半径−OP×OP) ……(4)
目的 :円周率を求める。
入力 :半径
処理 :Yを0から(半径−1)まで計算して加える
加えた値を上の式からπを求める。
出力 :計算したπの値
プログラム
100 input prompt "半径":rr
110 set window -1,rr,-1,rr
120 draw grid(10,10)
130
140 LET sum=0
150 for x=0 to rr-1
160 LET y=sqr(rr*rr - x*x)
170 LET sum=sum + y
180 plot
lines:x,0;
190 plot
lines:x,y
200 next x
210 print "半形:",rr
220 print "面積:",sum*4
230 print "PI:",sum*4/rr/rr
240 end
さて、実行してみましょう。
半径の長さが求められます。いま、100を入力します。
下のように、求めたPQの長さがグラフィックス表示されます。
求められたPIの値が表示されています。ちょっと値が変ですね。みんなが知っている3.14….とは値が少し多きですね。あとで、説明します。
解説
グラフィックスのための処理がプログラムされています。
初期設定 set window文で描画する領域の座標系を決めます。
Draw grid文は座標に格子を描きます。
線の描画 plot lines文で線を描きます。
BASICには沢山の数学関数が用意されています。平方根はsqr(数値)で求めることができます。この他にもあるので調べてみましょう
考察
みんなも気が付いたとおもいますが、求めたPIの値が少し大きかったよね。これは円の面積を求めるのに100等分してPQの値を求めたことに原因があるんだ。半径の値を大きくしていくとπが3.1412…にどんどん近づいくことがわかるよ。
コンピュータで行う計算には必ず誤差がつきまといます。したがって、コンピュータが出した結果がいつも正しいとうことにはなりません。誤差がどのくらいあるのかを知っておく必要があります。
5. ゲームを作ろう。
コンピュータゲームはあたかも知能を持っているように(持っているゲームもあるかも)、攻撃して来たり、不意に現れたりします。これは乱数という機能を使って簡単に不意な動作を作ることができます。これを使って簡単なゲームを作ってみましょう。
ゲームを作る前に、乱数について学びましょう。
コンピュータには乱数といって勝手に適当な数値(0以上、1未満の小数)を発生する機能があります。これを使って、まづ、サイコロを作ってみましょう。
目的 :電子サイコロを作る
入力 :なし
処理 :乱数を発生させる。0以上1未満を1から6に対応させる
出力 :1から6の値
プログラム
10 ! 電子サイコロ (乱数を用いて)
20 randomize
30 for i=1 to 10 !10回サイコロを振ります。
40 print
int(rnd*6)+1 !1から6の値を発生させます。
50 pause !一次停止、何かキーを押すと次に進みます。
60 next i
70 END
実行すると、10個の数値が現れます。毎回異なる数値が表示されるはずです。
解説
乱数を発生させる上で、毎回異なる値を発生させるためにrandomize文を書きます。これはサイコロを振る作業に似ています。
‘rnd文は0以上1未満の値を発生するので6を掛けて0以上6未満にします。更に1を加えることにより1以上7未満の値を発生します。
このままですと小数の扱いになるのでint(数値)関数を用いて1から6までの整数値を出力するようにします。
乱数はゲームや人工知能の分野で多く用いられています。
さて、ゲームを作ってみましょう。
画面上を飛び回るUFOを打ち落とすゲームです。「<」「>」キーで自機を左右に動かし、「スペースキー」でミサイルを打ち込みます。
プログラムは長いのでがんばってね
目的 :シューティングゲームを作る
入力 :「<」、「>」とスペースキー入力
処理 :UFOを乱数で移動させる。
自機を「<」「>」キーで移動させる。
スペースキーでミサイルを発射する。
UFOにミサイルがあたったら破壊され、次のUFOが現れる。
出力 :UFOの表示
自機の表示
ミサイルの表示
UFO撃墜の表示
100 DECLARE EXTERNAL FUNCTION INKEY$
110
120 set window -100,100,-5,100
130 draw grid(10,10)
140
150 randomize
160
170 !UFOの表示
180 LET ex=rnd*180-90 !UFOの最初の座標をex,eyに代入します。
190 LET ey=90 !UFOは必ずy座標が90の位置にいます。
200 LET ei=0 !UFOの移動するタイミングをとります。初期値0を代入します。
210 set point style 4 !UFOの形を決めます。○で表します。
220 set point color 7 !UFOの色をピンク色にします。
230 plot points:ex,ey !UFOを表示します。
240
250 !自機の表示
260 LET ix=0 !自機の最初の座標位置をix,iyに入れます。
270 LET iy=0
280 set point style 4
290 set point color 2 !自機の色は青色にします。
300 plot points:ix,iy !自機を表示します。
310
320 DO
330 LET ei=ei+1 !DO LOOP文を1回、処理するとeiは1つ増えます。
340 if ei=100
then !もし、100回ループしたら新しいUFOを発生させます。
350 set point style 4
360 set point color 0 !UFOを背景色と同じにしてもとのUFOを消します。
370 plot points:ex,ey !UFOを実際消します。
380
390 LET ex=rnd*180-90 !新しいUFOの座標位置を決めます。
400 LET ey=90
410 LET ei=0 !eiを初期化して100回まで、同じ位置を持続させます。
420 set point style 4
430 set point color 7 !UFOをピンク色に設定します。
440 plot points:ex,ey !overhead
450 end if
460
470 LET S$=INKEY$ !キーの入力、入力した値が1文字S$に入ります.
480 IF
S$<>"" THEN !変数S$に何か入っているとき
490 print S$
500 if S$="," then !”<”キーが入力したら左に移動する
510 set point
color 0 !現状の自機を消去する処理
520 plot
points:ix,iy
530 LET ix=ix-2 !x座標から2引いて左側の座標の値にする。
540 set point
color 2 !自機を表示する処理
550 plot
points:ix,iy
560 print ix,iy
570 end if
580 if S$="." then !”>”キーが入力したら右に移動する
590 set point
color 0 !現状の自機を消去する処理
600 plot
points:ix,iy
610 LET ix=ix+2 !x座標に2加えて右側の座標値にする。
620 set point
color 2 !自機を表示する処理
630 plot
points:ix,iy
640 print ix,iy
650 end if
660 if S$=" " then !スペースキーを入力したらミサイルを発射する
670 for i=0 to
100 !y座標の最大が100で、移動距離を表す。
680
set point color 3 !ミサイルの色を設定
690
plot points:ix,i !ミサイルを表示
700
print ix,i
710
set point color 0 !ミサイルを消去
720
plot points:ix,i
730 next I !0から100まで繰り返します。
740 if
abs(ex-ix)<5 then !UFOとミサイルの距離が5以内なら命中とする
750
set point style 3 !爆発(*)を表すスタイルにする
760
set point color 4 !色を赤色に設定
770
plot points:ex,ey !表示します。
780
beep
790
wait delay 1
800
LET ei=99 !次のエイリアンを発生させるために99を代入する
810 end if
820 set point
style 4 !自機のスタイルに変更
830 set point
color 2 !自機の色に変更
840 end if
850 end if
860 LOOP
870 END
880
890 EXTERNAL FUNCTION INKEY$ ! 関数の定義
900 SET ECHO "OFF"
910 LET S$=""
930 LET INKEY$=S$
940 END FUNCTION
さて、実行してみましょう。
下、中央にある青い○が君の機です。UFOは上空をピンク色の機体(○)です。スペースキーを押すとミサイルが飛んでいくのがわかります。自機の移動は<、>キーで行ってください。UFOは勝手に移動しますので、機敏に動いて打ち落としてください。
解説
プログラムの最初にある「DECLARE EXTERNAL FUNCTION INKEY$」は外部関数INKEY$の存在を宣言しています。実態の関数は890行がらかかれています。
細かい、解説は割愛します。楽しんでください。
プログラム中に、plot point文の同じようなパターンの繰り返しが存在しています。こうしたパターンを取り出してgosub文に置き換えることも可能です。今回の勉強ではプログラミングの流れを理解することが大きな目標ですので割愛しました。
考えてみよう
ゲームをしていくうちにもっと難しくしたり、強くしたりしたい要求が出てきます。プログラム中の値を変えてみて調べてみましょう。
1.自機の動きをもっと早くするにはどうするか
2.命中率を上げるにはどうするか
3.もっとスリルのあるゲームに仕上げるにはどうするか...ゲームはストリーが命…
●おわりに
今回の勉強ではプログラミングの基礎ということで、十分な説明ができていない点やBASICの機能を紹介できていない点など問題が多いとおもいます。しかし、プログラミングに触れてみて、コンピュータが自分の命令で動作することを実感できたのではないかとおもいます。今後も新しいプログラムを自分で工夫しながら作っていってもらえればと期待しています。今回使用した白石先生の「(仮称)十進BASIC
for Windows95」は非常に優れたBASICですので、将来、高校、大学でも実験の検証などに使っていけるものです。また、サンプルプログラムもたくさん含まれていますので、そちらを実行して勉強することも可能です。是非チャレンジしてください。