これで当カテゴリーでお話ししたいことはすべてお話しました。とはいっても当カテゴリーの目的は「平易なプログラミングを通してコンピュータの基本を学ぶこと」、主としてコンピュータのプログラミング入門者を対象としているので、コンピュータについての全てをお話しているわけではありません。また当カテゴリーの実習で使用したTiny Basic for Windowsについても、その全ての機能を網羅したわけではありません。
当カテゴリーの実習がきっかけでTiny Basic for Windowsをもっと深く勉強してみようという方は、ぜひ制作者のtakeuchiさんのサイトで勉強してください(下記リンクから行かれます)。
Tiny Basic for Windows
そしてコンピュータについてもっと専門的な知識を身に付けたいという方は、ぜひ機械語によるプログラミングに挑戦してください。演算、条件判断、繰り返し処理などをコンピュータがどうこなしているのかがわかります。
最後になりますが、ここまで頑張って読んでくださった皆様にこういうことを申し上げてたいへん申し訳ありません。プログラミング言語を覚えてプログラムが書けるようになっただけでは実用的なシステムが構築できるようにはなりません。システム構築ができるようになるためには、この後、システム設計の勉強をする必要があります。システム設計の第1歩は現状分析からですが、現状分析ができるようになるには、コンピュータの知識以前に対象の業務についての知識が必要です(筆者は昔、これで大っ恥かいた経験があります)。
そして出来あがったプログラムが目的通りに正しく動くかどうか、システムが目的どおりに間違いなく効率良く稼働するかどうか、これらが出来るようになるにはプログラムテスト、システム評価についての知識も必要です。これから職業プログラマ、SE(システムエンジニア)を目指そうと思っている方は、それらについて勉強していってください。
当カテゴリーがきっかけでふだんword、excelなどで使っているパソコンがどういう機械なのかということに皆様が目を向けてくだされば、コンテンツ制作者としてこれ以上の喜びはありません。
前章では、キーボードから入力したデータをファイルに書き込む(補助記憶装置に記憶する)プログラムを通して、コンピュータでのファイルについての基本を学びました。本章では、前章で作成したファイルを読み込むプログラムを通して、もう少しファイルを効果的に使うことを覚えましょう。前章同様、Word、Excelなどをすでに使っていて、ファイルについての基本知識がある方は※の節は読み飛ばしていただいてかまいません。
【補助記憶装置とファイル】※
前章では説明を省略しましたが、ドライブ名、フォルダ(ディレクトリ)、ファイルパスについてお話します。
[ドライブとフォルダ(ディレクトリ)]
図15-1.補助記憶装置のいろいろ
前章では補助記憶装置の説明としてCD/DVDドライブをとり上げましたが、補助記憶装置には図15-1のようにいろいろなものがあります。それぞれの装置の詳しい構造を知ることは本カテゴリーの目的から外れますのでここでは説明しませんが、外見からはわからなくともどの装置も駆動部、アクセス部(コントローラ)と記録媒体(不揮発性メモリ)で成り立っていることは共通しています。これらの補助記憶装置をすべてパソコンに接続した上で、WindowsシステムツールのPCを開くと図15-2のように表示されます。
図15-2.複数の補助記憶装置が接続された状態
図15-2の下半分のデバイスとドライブの部分を見ると現在接続されている補助記憶装置がわかります。ここで各装置のところに表示されているTIH0422000AやHD-PCGU3-Aなどをボリュームラベル(ボリューム名)といい、各補助記憶装置に付けられている名前とお考えください。ボリュームラベルはご自分の好きな名前に付け替えることができます。ボリュームラベルの後ろの(C:)や(F:)をドライブ名といいます(ドライブ名はお使いのパソコンにより異なります)。ボリュームラベルは長くて煩雑なので、プログラム中で補助記憶装置を扱うときはドライブ名を用います。
では、前章で作成したファイル、meibo.txtはどこに入っているのでしょうか。結論を先に言うとTiny Basic for Window(TBasic)sの場合、
OPEN "meibo.txt" FOR OUTPUT AS #1
のようにファイルパスを指定しないデフォルトの状態でファイルを作成するプログラムを走らせると、Tbasic.exeと同じ場所にファイルが出来ます。ここではTiny Basic for Windowsをusbメモリにインストール(【第0章】実習の準備参照)したものとして考えます。デバイスとドライブのTBasic.exeが入っているドライブをダブルクリックしてください(この例ではUSBメモリ)。すると図15-3のように表示されます。
図15-3.USBメモリをダブルクリックしたところ
黄色いノートみたいなアイコンが並んでいますが、これをフォルダ(ディレクトリ)といいます。1個のusbメモリを複数の目的に使う場合、ファイルをそのままでどんどん書き込んでいくと、後で見た時に「この作業に必要なファイルはどれだっけ」と探すのが大変になります。そこで目的別にファイルを分類しておくために、フォルダを作って、その中にファイルを書き込むようにします。この例ではTBasicというフォルダにTiny Basic for Windowsが入っています。ではTBasicというフォルダをダブルクリックしてみましょう。今度は図15-4のように表示されます。
図15-4.TBasicフォルダを開いたところ
Tiny Basic for Windows本体のTBasic.exeと前章で作成したプログラムとmeibo.txtという名のファイルが同じフォルダ内にあるのが確認できます。他にもいろいろなフォルダやファイルがありますが、これらはTiny Basic for Windowsをインストールしたときに自動的にコピーされたドキュメントやサンプルプログラムです。ここでmeibo.txtをダブルクリックするとWindows附録のメモ帳が起動し、中身を見ることができます(拡張子が .txt のファイルをダブルクリックすると自動的にメモ中が起動します)。ここでこのファイルの内容をメモ帳で変更・編集しないようにしてください。Enterキー(Returnキー)もダメです。ファイルの内容を変更・編集すると後で不具合が起こることがありますので充分気を付けてください。ファイルの内容が確認できたら、メモ帳を閉じてください。
1,青山 一丁目,アオヤマ イッチョウメ
2,秋田 鳥海,アキタ チョウカイ
3,麻布 十番,アザブ ジュウバン
4,石川 鶴来,イシカワ ツルギ
5,宇和島 愛媛,ウワジマ エヒメ
6,神奈川 鶴見,カナガワ ツルミ
7,島根 松江,シマネ マツエ
8,徳島 鳴門,トクシマ ナルト
9,長野 善光寺,ナガノ ゼンコウジ
10,盛岡 冷麺,モリオカ レイメン
図15-5.meibo.txtをメモ帳で開いたところ
[ファイルパス]
ここでいうパスとはpass(通行証/合格)ではなくpath(経路/道)です。対象のファイルまで辿り着く経路ということですが、前章で作成したmeibo.txtは図15-2から15-4のとおりの場所に作成されているとすると
Dドライブ(の媒体)の中のTBasicというフォルダの中のmeibo.txtというファイル
ということになります。これをTiny Basicでは
"D:¥TBasic¥meibo.txt"(¥はお使いのOS/ブラウザによっては\と表示されているかもしれません)
と書きます。ファイルパスの書き方は
ドライブ名:¥フォルダ名¥フォルダ名・・・・¥ファイル名
です。ファイルバスのうちドライブ名からフォルダ名は省略可能ですが、省略した場合(デフオルトのファイルパス)は、Tiny Basicの場合、TBasic.exeが入っている場所と同じ場所を指定したものとみなされます。
【ファイルを読み込むプログラム】
では、このmeibo.txtというファイルを読み込んで内容を表示するプログラムを作ります。手順は
①ファイルをINPUTモードで開く
②ファイルの内容を1行(1レコード)ずつ読み込み内容を表示する
③ファイルを閉じる
となります。プログラムは図15-6のようになります。2行目が手順①、3~6のWHILEブロックが手順②、7行目が手順③になります。
1:PRINT "*****名簿ファイル読み込み*****"
2:OPEN "D:\TBasic\meibo.txt" FOR INPUT AS #1
3:WHILE NOT EOF(1)
4: INPUT #1,BANGO,NAMAE$,KANA$
5: PRINT BANGO;" ";NAMAE$,KANA$
6:WEND
7:CLOSE #1
8:END
図15-6.ファイルを読み込むプログラム
ファイルの終わりを検知する
3行目にEOFというのが新しく出てきました。これはファイルの内容を1行ずつ読み込んでいって最後の行を読み終わったときtrue(真)となる関数です。End Of Fileの意味です。
EOF(ファイル番号)
のように書きます。
したがって、3~6行目のWHILEブロックは「ファイル番号1のファイル中のレコードをすべて読み込み終わるまで」ということになります。
ファイルの中身を読み込むにはINPUT命令を使いますが、INPUTの後ろに#ファイル番号を付けます(4行目)。次のように書きます。
INPUT #ファイル番号,変数,変数・・・・変数
今の例では1レコードのアイテムは番号(数値),名前(ストリング),ヨミガナ(ストリング)の順に並んでいるので、INPUT #1以後の変数の並びもこの型のとおりに合わせます(4行目)
5行目は読み込んだレコードの内容を表示しています。
これで最初の青山 一丁目さんから最後の盛岡 冷麺さんまで名簿ファイル中のすべてのレコードを読み込んで表示します。レコードを読み込んだところで、次のレコードがもうない(今読み込んだレコードが最後)だとEOFの値はtrue(真)になります。よって3行目のWHILE文に戻ったとき繰り返し終了条件は満たしたと判断され、WHILEブロックを抜けて7行目以降に移ります。ここで今使用したファイルを閉じてプログラム終了です。
【ファイルを2つ使うプログラム】
本カテゴリーで作成するプログラムもいよいよ最後となりました。ここでは少し実用的なプログラムをやってみましょう。といってもいきなり今までやってなかった命令や関数が出てくるわけではありません。ここまでで学んだ知識を組み合わせてできる範囲ですから、安心してください。
[プログラムの概要]
クラス名簿マスタファイルを読み込み、各々の生徒の試験の点数を入力し、試験データファイルを作成する
マスタファイルとは大元のファイルで内容が変わることは滅多にないもの、データファイルとは内容が変わることが頻繁にあるファイルです。
ファイル・レコードの形式
名簿マスタファイル
番号(数値),名前(ストリング),ヨミガナ(ストリング)
試験データファイル
番号(数値),点数(数値)
試験の点数
0点以上100点以下とする
図15-7.ファイルを複数使うプログラムのイメージ
1:PRINT "***** 試験の点数入力 *****"
2:INPUT "開始しますか(YES=1)",STARTOK$
3:IF STARTOK$<>"1" THEN
4: END
5:END IF
6:OPEN "meibo.txt" FOR INPUT AS #1
7:OPEN "shiken.txt" FOR OUTPUT AS #2
8:WHILE NOT EOF(1)
9: INPUT #1,BANGO,NAMAE$,KANA$
10: YN$=""
11: WHILE YN$<>"1"
12: PRINT BANGO;" ";NAMAE$,KANA$
13: DATAOK=0
14: WHILE DATAOK<>1
15: INPUT "点数(0-100)",TEN
16: IF TEN=>0 AND TEN<=100 THEN
17: DATAOK = 1
18: ELSE
19: PRINT "点数は0から100までです"
20: END IF
21: WEND
22: INPUT "これでよろしいですか(YES=1)",YN$
23: WEND
24: PRINT #2,BANGO;",";NAMAE$;",";KANA$;",";TEN
25:WEND
26:CLOSE #1,#2
27:END
1~5行目 誤実行防止
6行目 名簿マスタファイルを入力専用、ファイル番号1で開く
7行目 試験データファイルを出力専用、ファイル番号2で開く
8~25行目 名簿マスタファイルの全レコードを読み終わるまで繰り返す
9行目 名簿マスタファイルのレコード1件分の読み込み
11~23行目 入力した試験の点数が間違いなくなるまで繰り返す
12行目 今読み込んだレコードの内容を表示
14~21行目 入力した点数が正しくなるまで(0~100点の範囲内)になるまで繰り返す
22行目 入力した点数の確認
24行目 試験データファイルに出力
26行目 使用したファイルを閉じる
このカテゴリーもいよいよ終点に近づいてきました。この章と次章ではファイルを使うプログラムについて学びます。ファイルについて勉強するには、ファイル名、拡張子、補助記憶装置(媒体)などについても知る必要があります。本カテゴリーの目的は「プログラミング体験」と「プログラミング的思考を身につける」ですから、Windowsパソコン初心者の方でもわかるよう、この辺は必要最小限の範囲にとどめ、なるべく平易に説明します。またWord、Excelなどをすでに使っていて、ファイルについての基本知識がある方は※の節は読み飛ばしていただいてかまいません。
またTiny Basic for Windowsではファイルを取り扱う方法は①旧来の方法②.NET Frameworkに対応した方法(新しい方法)の2つがありますが、本カテゴリーではファイルとはどういうものかを知るために①の方法に基づいて説明します。
【ファイルとは】※
図14-4は一般的にファイルとよばれているもので、○月分売上伝票とか○年○組生徒指導要録など、同じ種類(目的)の書類をまとめておくのに使われます。
コンピュータのファイルも基本的にはこれと同じで①同じ種類(目的)のデータをまとめておくものです。ただコンピュータのファイルには②ある目的のための材料箱というものもあります。本カテゴリーでは①の意味でのファイルについて中心にお話します。
図14-1.事務用品のファイル
【ファイル・レコード、アイテム】※
ファイルとは同じ種類(目的)のデータをまとめておくものでした。たとえば担任クラスの生徒の名簿を考えてみます(図14-2)。
図14-2.名簿の例
これがファイルです。ファイルの中の1件1件のデータ(この例なら1行)をレコードといい、1件のレコードを構成する各項目(この例なら出席番号、氏名、ヨミガナ)をアイテムといいます。
プログラムを作るとき、最初に処理の手順(アルゴリズム)を考えたように、ファイルを使うには先にファイル設計をしておく必要があります。もし名簿が図14-3のようだったら、こんな名簿使いにくいことこの上ないですね。
図14-3.使いにくい名簿
このように1レコード中のアイテムの並びをどうするのか先に決めておくことが大切です。ここでは図14-2のように出席番号、氏名、ヨミガナの順としておきます。
【主記憶装置と補助記憶装置】※
図14-4.コンピュータを構成する各装置
第4章で出てきたこの図をもう一度復習しましょう。今のノートパソコンでは一見してもわかりませんが、コンピュータの中身は図14-4のようになっています。今までやってきたプログラム、たとえば次のプログラムは、図14-4の主記憶装置より上の部分(中央処理装置=Central Processing Unit=CPU、入力装置、出力装置、主記憶装置)だけを使っています。
INPUT "A=",A
INPUT "B=",B
C=A+B
PRINT "A+B=";C
END
ファイルを使うプログラムでは補助記憶装置(固定ディスク装置、CD/DVDドライブ、USBメモリ、SDカードなど)も使います。まず主記憶装置と補助記憶装置はどう違うのかを知っておきましょう。
上のプログラムの場合、キーボードから入力された2つの数を、それぞれ変数A、Bに記憶します。このとき2つの変数は主記憶装置内に自動的に格納されます。これは主記憶装置はCPUが直接管理しているからです。これに対してデータを主記憶装置ではなく、補助記憶装置に記憶する場合、①使用するファイルを開く②データをファイルに書き込む③ファイルを閉じるというステップを踏まなくてはなりません。これは補助記憶装置はCPUが直接管理していないため、使うための準備から後始末まで、すべてプログラムでやらなくてはならないからです。
【補助記憶装置と補助記憶媒体】※
ここで、何の説明もなく補助記憶装置という言葉を使いましたが、具体的な例でみてみましょう。目で見て最もわかりやすいCD/DVDドライブを例にとります。
図14-5.補助記憶装置(CD/DVDドライブ)
これはパソコン内蔵のCD/DVDドライブです。ここに音楽CDをセットすればパソコンをCDプレイヤーとして、映画やドラマなどのDVDをセットすればDVDプレイヤーとして使用することができます。そしてここに書き込み可能なCD-R、CD-RW、DVD-R、DVD-RW(以下、ディスクといいます)などをセットすれば、このCD/DVDドライブは補助記憶装置となります。上の写真をよく見ると、中心にセットしたCD、DVDを回転させる軸とディスクの内容を読み取ったり、ディスクにデータを書き込む光ヘッドがあるのが見えます。このような駆動装置、アクセス装置を総称して補助記憶装置といいます。
図14-6.補助記憶媒体(DVD-R)
この装置にセットするディスクのひとつが図14-6のDVD-Rです。補助記憶装置にセットして使用するディスク、USBメモリなどを補助記憶媒体(最近ではメディア、ストレージというようです)といいます。ファイルはこの補助記憶媒体に書き込まれます(記録されます)。
図14-7.補助記憶媒体を補助記憶装置にセットしたところ
このとおり補助記憶装置とは補助記憶媒体の内容を読み書きする装置のことなのですが、本カテゴリーでは煩雑さを避けるため補助記憶媒体をセットした状態(図14-7)を補助記憶装置と呼ぶことにします。
[主記憶装置と補助記憶装置の特性と欠点]※
①記憶容量
一般的に主記憶装置と補助記憶装置では補助記憶装置の方が記憶容量が大きいです。筆者のパソコンの場合、主記憶装置の記憶容量は8GB(ギガバイト)ですが、使用している補助記憶装置はいちばん容量が小さいもので500GBほどです。今日ではコンビニで売ってるUSBメモリやSDカードでも32GB、64GBくらいが普通になっています。なので全校生徒(児童)の指導要録などの大量の(容量の大きい)データはファイルとして補助記憶装置に、計算結果や処理中のデータは保存の必要がない限り主記憶装置内だけで扱うようにします。
②速度
主記憶装置と補助記憶装置では主記憶装置の方が記憶・記憶内容の読み出しの速度が速いです。今日のパソコン用補助記憶装置で一般的な事務処理プログラム程度ではあまり意識する必要はありませんが、画像・音声・動画を大量に扱う場合、補助記憶媒体への書き込み速度はシステム全体の運用効率にかなり影響が出ます。
③保存性
最後にこの節で最も大事なことを知っておきましょう。それは補助記憶装置の記憶は媒体が物理的に破損するか記録内容を消去するプログラムを実行しない限り永久に残るということです。これに対して主記憶装置の記憶内容はパソコンの電源を切るかパソコンを再起動かけたところですべて消えます。なので永久に保存しておきたいデータは補助記憶装置に記憶させるようにします。
【関数】
今まで何回かこの言葉を使ってきましたが、命令との違いについて説明してきませんでした。ここまでのレベルのプログラムではこの違いがわからなくてもとくに支障はありませんでしたが、コンピュータのコンピュータらしいプログラムを作るには、知っておいた方がいいことなのでここで勉強しましょう。
図14-1.数学の関数
図14-1.は中学校でも習う一次関数のグラフです。数学でいう関数とは伴って変わる数という意味です。プログラミング言語における関数はこの意味もありますがどちらかというと「マジシャンの箱」のようなものと考えてください。
図14-2.プログラミング言語の関数
マジシャンの箱はステッキで触れると中から鳩や万国旗が出てきますが(ネタ古っ)もちろんタネも仕掛けもあるわけです。プログラミング言語の関数とは、何か材料を入れると加工されて完成品が出てくる箱だと思ってください。この箱に入れる材料のことを引数(ひきすう)、箱から出てくる完成品を戻り値(もどりち)といいます。筆者の亡父が高校(旧制中学)の時使っていた数学の教科書では関数は「函数」と書かれていましたが、プログラミング言語の関数は函数と書く方が適切なような気がします。
Tiny Basic for Windowsの関数では引数が不要なものもあります。今まで出てきたサンプルプログラム中にもすでに登場している関数もあります。
[Tiny Basic for Windowsの便利な関数](一部)
SQR(正の数) 平方根を求める
INT(数) 数の小数点以下を切り捨てて整数化する
ROUND(数) 数の小数点以下を四捨五入して整数化する
RND 0以上1未満の乱数を得る(*1)
PI 円周率 3.14159265358979324 を得る(*2)
SIN(数) 正弦を得る(*3)
COS(数) 余弦を得る(*3)
TAN(数) 正接を得る(*3)
MAX(数1,数2) 数1と数2の大きい方を得る
MIN(数1,数2) 数1と数2の小さい方を得る
図14-3弧度法(ラジアン)span>
(*1)正式な書き方はRND(数)。普通に乱数を発生させる場合、数は正の数。省略した場合は正の数が指定されたものとみなす。
(*2)関数というよりプログラミング言語が提供する定数(予約変数)。
(*3)数は弧度法(ラジアン、図14-3)で与える。
A=5
B=SQR(A)
C=INT(B)
PRINT B,C
R=10
S=PI*R^2
PRINT S
END
2.2360679774997897 2
314.159265358979324
図14-4.数値関数のサンプルプログラムと実行結果
これらは戻り値が数値の関数なので数値関数とか数学関数とよばれます。プログラミング言語の関数には戻り値がストリングのストリング関数もあります。
DATE$ 現在の日付を yyyy/mm/dd形式で得る
TIME$ 現在時刻を hh:mm:ss形式で得る
LEFT$(ストリング,自然数) ストリングの左から(自然数)分文字の文字を得る
RIGHT$(ストリング,自然数) ストリングの右から(自然数)分文字の文字を得る
LEN(ストリング) ストリングの文字数を得る(戻り値は数値)
MID$(ストリング,自然数1,自然数2) ストリングの左から(自然数1)文字目から(自然数2)文字分の文字を得る
NOW$=DATE$+" "+ TIME$
L=LEN(NOW$)
Y$=LEFT$(DATE$,4)
M$=MID$(DATE$,6,2)
D$=RIGHT$(DATE$,2)
PRINT NOW$,L
PRINT "今年は";Y$;"年です"
PRINT "今日は";M$;"月";D$;"日です"
END
2023/04/26 11:37:30 19
今年は2023年です
今日は04月26日です
図14-5.ストリング関数のサンプルプログラムと実行結果
これらの関数はプログラミング言語が提供しているものなので組込関数とよばれることもあります。
【ストリングの長さ】
※この節は昔のBASICをやったことのない方には???かもしれません。今のTiny Basicのプログラミングだけ覚えたい、という方は今は読み飛ばしていただいてかまいません。
1:STRG1$="ABCDE"
2:STRG2$="東京大阪福岡"
3:PRINT STRG1$,STRG2$
4:PRINT
5:L1=LEN(STRG1$)
6:L2=LEN(STRG2$)
7:PRINT L1,L2
8:PRINT
9:C1$=MID$(STRG1$,3,2)
10:C2$=MID$(STRG2$,3,2)
11:PRINT C1$,C2$
12:END
図14-6.Tiny Basicのストリング長を調べるプログラム
図14-7.ストリング長を調べる
図14-6のプログラムの実行結果は図14-7のようになります。Tiny Basicでは日本語(全角文字)も含めて「見える1文字」は1文字と数えます。同じプログラムを昔のBASICで実行すると図14-8のようになります。
図14-8.昔のBASICでのストリング長
昔のBASICでは半角英数字・記号・カタカナは1文字1バイト、日本語(全角文字)は1文字で2文字と数えます。昔のBASICから今のTiny Basicに乗り換える場合、注意が必要なところです。
【サブルーチン】
コンピュータの得意技のひとつがデータの保存と再利用でした。同じように処理の再利用もできます。図14-8のプログラムの10~13行目はサブルーチンとよばれ、プログラムの他の箇所から呼び出されて使われます。13行目のRETURNは呼び出し元に戻る命令です。サブルーチンは何度でも呼び出して使えます。サブルーチンを呼び出して使う側(図14-6のプログラムなら1~9行目)をサブルーチンに対しメインルーチンと呼びます。制御文ブロックが構成できるTiny Basicでこの程度のプログラムではこのような単純なサブルーチンを使う意味はほとんどありませんが、ある制御文ブロック中の処理を別のブロックで使いたい時には使います。Tiny Basicでサブルーチンをサブルーチンらしく使う場面は、関数を自作する場合です(当カテゴリーでは扱いません)。
1:RESTORE *EKIMEI
2:EKI$=""
3:WHILE EKI$<>"//"
4: READ EKI$,SHA$,SEN$
5: IF EKI$<>"//" THEN
6: GOSUB *DISP
7: END IF
8:WEND
9:END
10:*DISP
11:TXT$=EKI$+"駅は"+SHA$+SEN$+"の駅です"
12:PRINT TXT$
13:RETURN
14:*EKIMEI
15:DATA "厚岸","JR北海道","根室本線"
16:DATA "谷田川","JR東日本","水郡線"
17:DATA "合格","大井川鉄道","大井川本線"
18:DATA "教会前","JR四国","鳴門線"
19:DATA "東新庄","富山地方鉄道","宇奈月本線"
20:DATA "//","",""
厚岸駅はJR北海道根室本線の駅です
谷田川駅はJR東日本水郡線の駅です
合格駅は大井川鉄道大井川本線の駅です
教会前駅はJR四国鳴門線の駅です
東新庄駅は富山地方鉄道宇奈月本線の駅です
図14-8.サブルーチンを用いたプログラム例と実行結果
【サブルーチンのネスティングと変数の値引継ぎ】
1:A=0
2:PRINT "メインルーチンスタート"
3:GOSUB *SUB_1
4:GOSUB *SUB_2
5:PRINT "A=";A,"B=";B
6:PRINT "プログラム終了"
7:END
8:
9:*SUB_1
10:A=A+1
11:PRINT "サブルーチン1を実行しました";I
12:RETURN
13:
14:*SUB_2
15:A=A+10
16:B=5
17:GOSUB *SUB_1
18:PRINT "サブルーチン2を実行しました";I
19:RETURN
図14-9.サブルーチン間で変数を引継ぐプログラム
図14-9のプログラムでは、メインルーチンの3行目まできたところでサブルーチンへ飛びます(この例では*SUB_1以後)。サブルーチン内の12行目まできたところでRETURNなのでメインルーチンに戻ります。戻り先はこのサブルーチンを呼び出した次の行です(ここでは4行目)。4行目はまたサブルーチンへのジャンブ(今度は*sub_2以後)です。サブルーチンの17行目までくると、またサブルーチン(*sub_1以後)へジャンプします。12行目のRETURNですが、今度は戻り先が18行目になります。サブルーチンもFOR制御文、WHILE制御文のようにネスティングができます。実行結果は図14-10のようになります。
図14-10.サブルーチン間での変数引継ぎ
ところで、実行結果を見ていただければおわかりと思いますが、変数Aの値はメインルーチンからサブルーチン、また別のサブルーチンへ引き継がれていることがわかります。また変数Bは2つ目のサブルーチン内で初めて出てきたものですが、その値はメインルーチンに戻っても引き継がれます。普通のサブルーチンの使い方では変数の値はメインルーチンとすべてのサブルーチン間で引き継がれます。このようにプログラム中のすべての場所で値が引き継がれる変数をグローバル変数といいます。引き継がれるということは、たとえばサブルーチン内でメインルーチン内で使用している変数を誤って使ってしまうと、変数の値を壊してしまうことになります。これに対し特定の範囲でのみ有効な変数をローカル変数といいます。Tiny Basicや昔のBASICでは、自作の関数内で使用する変数以外はすべてグローバル変数になります。
【昔はよかったなぁ】
今のTiny Basicではあまり出番のないサブルーチンですが、(IFブロックがなかった)昔のBASICではなくてはならないものでした。図14-9のプログラムは第12章の図12-7のプログラムをサブルーチンを使うよう書き換えたものです。IFブロックが使えない昔のBASICでは、条件が成立したとき(またはしなかったとき)の処理が数十行に及んだり、その中にまた別の制御文が入ったりするときは、サブルーチンを使わなければ事実上プログラミングは不可能でした(プログラムの1行が255文字以内という制限があったため)。
図14_9サブルーチンを使ったプログラム例span>
この最初の行(行番号10)のGOTO 1000を見て「懐かしい」と思われた方、昭和プログラマ同窓会やりましょう🍺🍶🍣。
冗談はさておき、このプログラムは行番号1000~1200がメインルーチン、100~320行目がサブルーチン群です。最初の行のGOTO 1000がないと、プログラムは行番号100からメインルーチンとして開始されます。そして行番号190にきたところで「RETURN?ってどこへ帰ればいいんだ?」となり、コンピュータは止まってしまいます。これを避けるために、プログラム開始直後にサブルーチン群を飛ばしてメインルーチンの頭から実行するように、先頭にGOTO命令が置かれます。昔はなんでこんな面倒なプログラムの書き方をしたのかというと、昔のBASICではこのようにサブルーチンを最初に、メインルーチンを後ろに置いた方がメモリ節約になったからです。メモリが32Kのパソコンでまともなプログラムを書くには必須テクニックでした。GOTO命令はたしかにあまり使いたくない命令なのですが、サブルーチンが多いプログラムではなくてはならない命令だったのです。
【この章のまとめ】
材料(引数)を渡して完成品(戻り値)が出てくる箱を関数という。
プログラム中で何回も出てくる処理はサブルーチンにして呼び出して使うことができる。
サブルーチンはネスティングできる。
プログラム中のどこでも値が引き継がれる変数をグローバル変数、特定の範囲でのみ有効な変数をローカル変数という。
今まで堅苦しいプログラムばかり作ってきましたが、ちょっと楽しいプログラムを作ってみましょう。そう、ゲームのプログラムです。コンピュータゲームというと「ゲームばかりやってないで勉強しなさい」とお父さんお母さんに叱られたとかオンラインゲームで課金し過ぎてお金がなくなったとかあまりいい話を聞きませんがそれはゲームで遊ぶ側の話です。そのゲームのプログラムを作るということになると話は違ってきます。ゲームのプログラム1つ作る過程でプログラミングの高度なテクニックや様々なアルゴリズムを学ぶことができます。筆者はゲームを作りながらプログラミングの勉強をすることは否定しません。ということでこのカテゴリーでも実際にゲームのプログラムを作ってみたいと思います。とはいっても 残念ながらTiny BASIC for Windowsでテキスト画面のみでは、画面いっぱいに敵戦闘機が飛び回るとか、クエストクリアしたら美少女が微笑むようなゲームは無理ですが、ストリングと計算式のみでも知育ゲームやアドベンチャーゲームのようなものはできます(なんか美少女のたとえが多くね?・・・汗)。
[乱数]
ゲームで必須なものは乱数です。乱数とは、規則性のない数の並びのことです。たとえば2、3、4、6なら12の約数を小さい順に並べたものとわかりますが、4、7、2、9だとまったく規則性がありません。ゲームでは敵がどこから襲ってくるかわからない、どこに何が隠れているかわからないなど、ランダムに何かが出てくるという場があります。これを実現かるのが乱数であり、Tiny BASICにはこの乱数を発生させる機能があります。それが次のRND(*)です。次のプログラムを実行してみてください。
FOR I=0 TO 10
R=RND
PRINT R
NEXT I
実行結果は図13-1のようになります。
図13_1.乱数を発生する
RNDは0以上1未満の乱数を発生する関数(後述)です。ただしひとつ注意することがあります。上のプログラムを何回か実行してみてください。おわかりと思いますが乱数とはいってもコンピュータで発生させる場合ある計算式にしたがって発生させるので、同じプログラムを繰り返し実行すると、発生する数の順番はいつも同じになってしまいます。これではたとえばシューティングゲームに使うにしても、敵が出てくる場所と順番がいつも同じになってしまい、面白みが半減ですね。これを回避するには、次のようにRANDOMIZE(*)という一文をRNDの前に入れます。これはコンピュータの内部時計を用いて、乱数発生の計算式の初期化を行なうものです。
RANDOMIZE
FOR I=0 TO 10
R=RND
PRINT R
NEXT I
これで数回実行してみましょう。今度は発生する数の順番はバラバラになったはずです。では、これで1から10までの整数をランダムに発生させる方法を考えてみましょう。RNDで発生する数は0以上1未満ですから
RANDOMIZE
R=RND*10+1
で 1 から 10 までの数がランダムで得られます。さらに
RANDOMIZE
R=INT(RND*10)+1
とすると、発生した数の小数点以下が切り捨てられ1から10までの整数がランダムで得られます。INTはInteger(整数の意味)の省略形でINT(数値)で( )内の数値の小数点以下を切り捨てて整数化する関数です。次のプログラムで試してみてください。結果は図13_2のようになります。
RANDOMIZE
FOR I=1 TO 10
R=INT(RND*10+1)
PRINT R
NEXT I
END
図13_2.1から10の整数をランダムに発生させる
(*)RANDOMIZEとRNDの正式な書き方は
RANDOMIZE 整数(-32768~32767の範囲)
RND(整数)
ですが、Tiny Basicでは、どちらも整数は省略可です。省略しても不規則な数を発生します(図13-3)。普通のゲームプログラムならこれで問題ないと思います。
図13_3.1から100の整数をランダムに発生させる
[数当てゲームのプログラム]
それでは、ここまでの知識を使って簡単なゲームを作ってみましょう。コンピュータが隠した 1 から 100 までの整数を当てるゲームです。図13-4のプログラムを見てください。
1:CLS ' 画面をクリア
2:RANDOMIZE ' 乱数系列の初期化
3:PRINT "***** 数当てゲーム *****"
4:PRINT "今からコンピュータが隠した数を当ててください"
5:PRINT "数は 1 から 100 の整数のみです"
6:' 乱数を発生させる
7:R=INT(RND*100)+1
8:' 数を当てる
9:' 正解が出るまで以下の処理を繰り返す
10:DATAOK=0
11:WHILE DATAOK=0
12: PRINT
13:' 1~100の整数が入力されるまで繰り返す
14: NUMOK=0
15: WHILE NUMOK=0
16: INPUT " 1~100で数を当ててください",NUM
17: PRINT
18: IF NUM=>1 AND NUM<=100 THEN
19: NUMOK=1
20: END IF
21: WEND ' 1~100の整数が入力されるまで繰り返しここまで
22:
23:' 正解判定
24: IF NUM=R THEN
25:' 正解のとき
26: PRINT "正解です。おめでとうございます"
27: DATAOK=1
28: ELSE
29:' 正解ではないとき
30: IF NUM
32: PRINT "小さすぎます"
33: ELSE
34:' 大きすぎるとき
35: PRINT "大きすぎます"
36: END IF
37: END IF
38:WEND ' 正解が出るまでの繰り返しここまで
39:END
図13-4.数当てゲームのプログラム
プログラムスタート部分の1行目のCLSはCLear Screenの省略形で実行画面をすべて消去する命令です。表示が消去されるだけで記憶されているプログラムやデータが消去されるわけではありません(黒板消しのようなものです)。
2行目は今、説明した乱数の初期化です。3~5行目はプログラムと遊び方の説明です。
7行目がコンピュータが隠す数を発生させるところですが、ここでは1から100までの数を発生させることにします。
プログラム全体の流れとしては、最初にコンピュータが数を隠した後、正解が出るまで答えの入力を繰り返し実行されるようになっています。そしてプレイヤーが答えた数が1~100以外の数以外のときは入力がやり直しになるようになっています。それは11、38行目のWWHILE~WENDと15行、20行目のWHILE~WENDのネスティングで実現しています。この手法は実務プログラムではオペレータの入力ミスを防ぐ対策としてよく使われるものです。覚えておいて損はありません。
19、29行目のIF~END IFは正解不正解の判定です。正解ならこのプログラムを終了するように、不正解なら回答した数が大き過ぎか小さ過ぎかを表示するようにしています。
図13_5.数当てゲームの実行画面
【いろいろなエラー】
ここまでいろいろなプログラムを作ってきた皆さんは、いろいろなエラーを出してきたと思います。エラー(error)とは「誤り」とか「失敗」という意味です。何回もエラーを出して「俺にはプログラミングの才能なんてないんだ」と落ち込んでいる人はいませんか。気にする必要はありません。勉強中はむしろどんどんエラーを出してください(*)。筆者の経験で言えば、エラーを出してそれを修正してゆく中で学べるものはたくさんあります。
(*)Perl、PHP、C言語、アセンブリ言語などハードウェア、サーバーを直接操作するプログラミング言語の場合、パソコンをローカル環境(ネットワークから切り離したスタンド・アローンな状態)にして勉強してください。
プログラミングで発生するエラーは大別すると次の3つになります。
①文法エラー(Syntax error)
文法エラーというより構文エラー(書き方の誤り)です。たとえば次のプログラムを実行しようとすると、図14-6のような状態でコンピュータは止まってしまいます。
1:GOKEI=0
2:NINZU=0
3:BANGO$=""
4:WHILE BANGO$<>"//"
5:READ BANGO$,NAMAE$
6: IF BANGO$<>"//" THEN
7: PRIMT BANGO$;" ";NAMAE$;" ";
8: INPUT "得点="・,TEN
9: GOKEI=GOKEI+TEN
10: NINZU=NINZU+1
11: END IF
12:WEND
13:NINZU=NINZU-1
14:HEIKIN=GOKEI/NIN
15:PRINT USING "受験者 ##人";NINZU
16:PRINT USING "平均点###.#";HEIKIN
17:END
18:DATA "001","相沢 恭平"
19:DATA "002","小川 順子"
(中略)
54:DATA "037","渡部 浩司"
55:DATA "//",""
図13-6.文法エラー
プログラムの7行目を見ると、PRINTと書くべきところがPRIMTになっています。Tiny Basicにこんな命令はないので(変数とみなされてしまうため)、その後に続く内容と矛盾が生じてしまい、コンピュータが???状態になってしまったわけです。
②実行エラー(execute error/running error)
文法(書き方)の誤りはなくても、プログラム実行中に発生するエラーがあります。次の例は処理不可能なデータに当たってしまったコンピュータが「こんなのやってらんねぇ」となってしまった例です。
上のプログラムを修正して次のようになりました。これを実行してみたところ図13-7のようになりました。
1:GOKEI=0
2:NINZU=0
3:BANGO$=""
4:WHILE BANGO$<>"//"
5:READ BANGO$,NAMAE$
6: IF BANGO$<>"//" THEN
7: PRINT BANGO$;" ";NAMAE$;" ";
8: INPUT "点数 ",TEN
9: GOKEI=GOKEI+TEN
10: NINZU=NINZU+1
11: END IF
12:WEND
13:NINZU=NINZU-1
14:HEIKIN=GOKEI/NIN
15:PRINT USING "受験者 ##人";NINZU
16:PRINT USING "平均点###.#";HEIKIN
17:END
18:DATA "001","相沢 恭平"
19:DATA "002","小川 順子"
(中略)
54:DATA "037","渡部 浩司"
55:DATA "//",""
図13-7.実行エラー
プログラム14行目は得点の合計を受験者数で割って平均点を計算するところですが、除数になる変数名がNINZUであるべきところNINになっています。この場合、プログラムの書き方としては誤っていないので文法エラーにはならずプログラムは実行開始されます。しかし変数NINの値は 0 なので14行目で処理不可能となり止まってしまいました(除数が0の割り算は不可能なのは算数でもコンピュータでも同じです)。
➂論理エラー(logical error)
プログラムの文法上の誤りも入ってくるデータにも誤りはないのに、処理内容の誤りにより正しい処理結果が得られないエラーです。簡単な例で説明します。
次の例はキーボードから単価と売上個数を入力し売上金額を計算するプログラムなのですが、単価100円、個数5と入力したところ金額が500円となるところが105円になってしまいました。
1:INPUT "単価=",TANKA
2:INPUT "個数=",KOSU
3:KINGAKU=TANKA+KOSU
4:PRINT "金額=";KINGAKU
5:END
図13-8.論理エラー
誤り箇所はプログラム3行目です。
KINGAKU=TANKA*KOSU
とするべきところが
KINGAKU=TANKA+KOSU
になっています。この場合、プログラムの書き方に誤りはなく、データも変数TANKAの値が500、変数KOSUの値が5なので、KINGAKU=TANKA+KOSUの計算は問題なくできます。なのでプログラムは途中で止まらず最後まで実行されます。しかし得られた結果は求めているものではない、ということになります。
このように論理エラーは途中でコンピュータが止まってしまうことがないので発見と修正が最もやっかいなエラーといえます。ゆえにこのような誤りのことを、みつけにくいという意味でバグ(bug、ダニのような小さな虫)、バグをみつけて修正することをデバッグといいます。
コンピュータはたとえて言えば「忠実だけど融通がきかない部下」です。
「課長、この指示はこれでいいんですか?」
「おぅ、ありがとう。ここは間違い、こうしてくれ」
とはなりません。指示書が間違っていようが渡されたデータに誤りがあろうが、そのとおりに実行しようとします。たとえその結果、会社が倒産(システムがダウン)するとしてもです。コンピュータの計算(処理結果)が正確なのは正しいプログラムとデータが与えられていれば、の話です。
【この章のまとめ】
ゲームの主役は乱数である。
RNDは乱数を発生する関数である。
RANDOMIZEは乱数系列を初期化する。
プログラミング上のエラーには文法エラー実行エラー、論理エラーがある。
プログラムのミスをバグ、バグをみつけて修正することをデバッグという。