はじめての方は「ごあいさつ」からご覧ください。(新しい記事順に並べています)

------------------------------------------------------------
目次
------------------------------------------------------------
第9回 山崩しゲーム/解説編
第8回 山崩しゲーム/本編
第7回 山崩しゲーム/続準備編
第6回 山崩しゲーム/準備編
第5回 ライフゲーム/動作編
第4回 ライフゲーム/本編
第3回 ライフゲーム/準備編
第2回 πの計算/改定版
第1回 ルート2の計算
ごあいさつ


------------------------------------------------------------
記事中のプログラムリスト
------------------------------------------------------------
プログラム1,2,4 (list_su1.txt)
プログラム8 (list_su2.txt)


■第9回 山崩しゲーム/解説編(2017/02/04掲載,2017/02/05最終変更)
前回で、山崩しゲームのプログラミングは終了しました。
今回は、このプログラムで使用したマイクロBASIC特有の表現について説明します。(*1)

(1)条件分岐
マイクロBASICでは、GOTO文を、#=行番号と書きます。
これだけであれば、単に「GOTO」が代入式の表記(#=)に置き換わっただけなのですが、右辺に数式を書くことができます。
例えば
#=(A>10)*120
で、(A>10)の部分は論理式で、Aが10を超えるなら値1、Aが10以下なら値0となるので
Aが10を超えるなら、#=120
Aが10以下なら 、#=0
という意味になります。
マイクロBASICは、飛び先として行番号0を無視する仕様になっているので、Aが10を超えるときのみ行番号120へジャンプすることになります。
これは
IF A>10 THEN 120
と同じ動作をします。
この機能(飛び先として行番号0を無視する)のメリットは明確で、新たにIF文を実装する必要がないことです。本プログラムでは
1230 #=(N>99)*1220
などにこの構文を使っています。

(2)サブルーチン
マイクロBASICでは、GOTO文とGOSUB文は同じ表現(#=行番号)です。
GOSUB文をGOTO文と同じ表現にしたら、RETURN文のときに戻る行番号がスタックに積まれていないのでは?というあなたは正常です。

もちろんカラクリがあります。
実は、VTL言語処理プログラムは、#=行番号のとき変数!に現在の行番号+1の値を入れておきます。
このため、サブルーチンリターンのとき、#=!とするとサブルーチンをコールした行番号+1に戻ることができます。
欠点は、戻り先のスタックは1レベル(変数!)ですので、サブルーチン内で#=行番号を使えません。
もし使うと、変数!は上書きされてサブルーチンからリターンできなくなってしまいます。
回避策は、変数!が書き換えられる前に別の変数に退避しておくことです。本プログラムでは
1610 #=2200 ← GOSUB文に相当

2200 (STEP11)
2210 S=! ← サブルーチン内で#=を使うので、変数!を変数Sに退避
2220 L=0
2230 L=L+1
2240 #=(L<150)*2230 ← IF文に相当する#=を使う(変数!が壊れる)が、行番号2220で変数!は退避済み
2250 #=S ← RETUR文に相当

で、この構文を使っています。
マイクロBASICでは、GOTO文、IF~THEN文、GOSUB文、RUTURN文をすべて#=で済ませていることになります。(*1)

(3)AND、OR演算子
マイクロBASICでは、AND、ORがありません。例えば
IF (A=1)OR(A=3)OR(A=5) then 2000
を、マイクロBASICではORの代わりに+を使って
#=(A=1)+(A=3)+(A=5)*2000
と書きます。
もう、マイクロBASICに慣れたと思いますので説明不要かと思います。本プログラムでは
1360 #=(Y=0)+(Y=N)+(Y>N)*2100
などに、この構文を使っています。同様に、ANDは*が使えます。

さて、今回で山崩しゲームは終了とします。
次回は、変わったテーマを扱う予定です。(*2)
--------------------
(*1)#=行番号は、戻り先を記憶するスタックのサイズが1のGOSUB文で、#=!を使わなかった場合は「結果的に」GOTOと同じ動作をするというのが 本質的な解釈と思います。
(*2)参考文献
「エンサイクロペディア・アスキーVolume1、Altair680とマイクロBASIC(アスキー出版)」

■第8回 山崩しゲーム/本編(2017/01/04掲載,2020/05/31最終変更)
今回は山崩しゲームのプログラムを作成し動作させてみます。
ゲームの設計は、ほぼ第6回の説明の通りです。
具体的には、次のアルゴリズムとします。

ステップ1 ゲームの説明を表示する
ステップ2 乱数(範囲21~99)で石の初期値Nを決め、表示する
ステップ3 最初に人間に取る石の数Yを聞き、残りの石の数Nを計算・表示する、範囲外ならゲーム終了(ステップ10へ)
ステップ4 現在の石の数Nが21以上なら、コンピュータの取る石の数Iを10(ただし、上限2Y)とし、表示する
現在の石の数Nが20以下なら、コンピュータの取る石の数Iを最小フィボナッチ数(*1)(ただし、上限2Y)とし、表示する
ステップ5 残りの石の数Nを再計算・表示する、残り0なら人間の負け(ステップ8へ)
ステップ6 人間に取る石の数Yを聞き、ルール違反なら人間の負け(ステップ8へ)
ステップ7 残りの石の数Nを再計算・表示する、残り0ならコンピュータの負け(ステップ9へ)、そうでなければ継続(ステップ4へ)
ステップ8 人間の負けを表示、再ゲームへ(ステップ2へ)
ステップ9 人間の勝ちを表示、再ゲームへ(ステップ2へ)
ステップ10 プログラム終了
ステップ11 ディレイサブルーチン


また、プログラム中で使用している変数は次の通りです。

変数N(現在の石の数)
変数I(コンピュータの手)
変数Y(人間の手)
変数R(乱数計算用変数)
変数Z(キー入力待ちダミー変数)
変数J(コンピュータの手の計算補助)
変数S(サブルーチン戻り値退避)


以上で設計終了です。
では、この設計通りプログラミングしていきます。

【プログラム8】山崩しゲーム(#=1000で実行)

--- ゲームを開始するまでの準備(ステップ1~3) ---

1000 (PROGRAM8)
1010 "YAMAKUZUSHI"
1020 Z=?

1100 (STEP1)
1110 R=0
1120 "AITENO TOTTA 2BAI";
1130 " MADE TORERU";
1140 Z=?
1150 "SAIGO WO TORU";
1160 " TO KACHI";
1170 Z=?

1200 (STEP2)
1210 N=@(R)
1220 N=N/3+21
1230 #=(N>99)*1220
1240 "STONE=";
1250 ?=N

1300 (STEP3)
1310 "YOU(1-";
1320 ?=N-1;
1330 ")?";
1340 Y=?
1350 R=R+Y
1360 #=(Y=0)+(Y=N)+(Y>N)*2100
1370 N=N-Y
1380 "STONE=";
1390 ?=N


--- ここから、勝敗が決まるまで繰り返す(ステップ4~7) ---

1400 (STEP4)
1410 #=2200
1420 J=(N=1)+(N=4)+(N=6)+(N=9)
1430 J=(N=12)+(N=14)+(N=17)+J
1440 J=(N=19)+J
1450 J=(N=2)+(N=7)+(N=10)*2+J
1460 J=(N=15)+(N=20)*2+J
1470 J=(N=3)+(N=11)+(N=16)*3+J
1480 J=(N=5)*5+J
1490 J=(N=8)+(N=18)*8+J
1500 J=(N=13)*13+J
1510 J=(N>20)*10+J
1520 #=(2*Y<J)*1550
1530 I=J
1540 #=1560
1550 I=2*Y
1560 "I=";
1570 #=2200
1580 ?=I;

1600 (STEP5)
1610 #=2200
1620 ""
1630 N=N-I
1640 "STONE=";
1650 ?=N
1660 #=(N=0)*1900

1700 (STEP6)
1710 "YOU=";
1720 Y=?
1730 #=(Y=0)+(Y>N)*1900
1740 #=(2*I<Y)*1900

1800 (STEP7)
1810 N=N-Y
1820 "STONE=";
1830 ?=N
1840 #=(N=0)*2000
1850 #=1400


--- 以下は、終了処理(ステップ8~11) ---

1900 (STEP8)
1910 "**YOU LOSE**";
1920 Z=?
1930 #=1200

2000 (STEP9)
2010 "**YOU WIN**";
2020 Z=?
2030 #=1200

2100 (STEP10)
2110 "**END**"
2120 #=65535

2200 (STEP11)
2210 S=!
2220 L=0
2230 L=L+1
2240 #=(L<150)*2230
2250 #=S


このプログラムを動作させたところ、漠然とゲームを進めるだけでは、まずコンピュータに勝てません。
人間が先手なので圧倒的に有利なはずなのですが、コンピュータは石の数が20個以下になると正確に最適な石の数を取ってきます。
ちなみに、私は1回も勝たせてもらっていません。f(^_^;

次回はこのプログラムリストで使用したマイクロBASIC特有の表現(テクニック)について説明します。
--------------------
(*1)第7回の(式1)参照

■第7回 山崩しゲーム/続準備編(2016/12/25掲載,2017/01/04最終変更)
前回(第6回)の冒頭で説明した通り、前回の説明には私のミスで間違いがあります。
間違いは「先手必勝法」の説明です。

(誤)先手必勝法-現在の石の数を「フィボナッチ数の和」で表し、その中の一番小さなフィボナッチ数の石を取る
(正)先手必勝法-現在の石の数を「隣合わないフィボナッチ数の和」で表し、その中の一番小さなフィボナッチ数の石を取る

すなわち、現在の石の数は「フィボナッチ数の和」ではなく「隣合わないフィボナッチ数の和」で表すのが正解です。
そうしないと、その中の一番小さなフィボナッチ数の石を取っても、次に相手(後手)に残りすべてを取られてしまうことがあるためです。

では、実例を考えてみます。

(例1)石の数が5個でゲームが始まった場合
ここで先手が誤って、石の数を普通にフィボナッチ数の和(5=0+2+3)(*1)で表したとします。(隣り合った部分2+3があります)
先手は、必勝法に従ってその一番小さなフィボナッチ(2)個の石を取ります。
後手は、先手が2個取ったので最大4個までの石を取ることができるので、残りの石(3個)を全て取ることができ、後手の勝ちとなります。
先手が負けた原因は「隣合わないフィボナッチ数の和」でなかったからです。

(例2)石の数が17個でゲームが始まった場合
まず、石の数17をフィボナッチ数(1,2,3,5,8,13,21,34,55,89,144,…)の和で表してみます。
次の2つのパターンが考えられます。
パターン1 17=1+0+3+0+0+13 (隣合わないフィボナッチ数の和)
パターン2 17=1+0+3+5+8 (8+5+3の部分で隣り合っているフィボナッチ数の和)
この場合、17をパターン1で表し、その中の一番小さなフィボナッチ数(1)の数の石を取るのが正解です。
これは「相手が直前に取った石の2倍を超える石を取ってはいけない」というルールがあるために、後手は次に残りすべての石を取ることができないた めです。


一般的に石の数がn=0+…+A+0+Bで、ここから先手がA個を取った場合、後手は残りのB個すべてを取ることはできません。
なぜなら、フィボナッチ数の性質からB>2Aであるため、仮に2倍(2A個)取ったとしても石が余ってしまう(B-2A>0)からです。(ここ重 要!)

後手が石を取ったら、先手は残った石を再び「隣合わないフィボナッチ数の和」で表し、その中の一番小さなフィボナッチ数の石を取ると、また後手は 残りの全てを取ることはできません。
すなわち、後手は常に勝てない状態で手を渡されていることになり、そのうち先手が全ての石を取ってゲーム終了となります。

なお、一般にすべての整数は「隣合わないフィボナッチ数の和」で表わせるらしいのです。
ここでは、1~20までの「隣合わないフィボナッチ数」の最小数(式1、fnと表記)が解れば十分です。

f1=1,f2=2,f3=3,f4=1,f5=5,f6=1,f7=2,f8=8,f9=1,f10=2,f11=3,f12=1,f13=13,f14=1,f15=2,F16=3,f17=1,f18=5,f19=1,f20=2 (式1)(*2)

ここまで来て、先手必勝法の例外に気が付きました。
先手は、常に一番小さなフィボナッチ数を取ればよいのですが、次のルールにより取れない場合があります。

ルール1-先手の第1手目では、全部の石を取ってはいけない。

実は、先程の例(石の数が5個でゲームが始まった場合)がこれに相当します。「隣合わないフィボナッチ数の和」で表すと

5=0+0+0+5

なので、先手は5個すべて取るべきなのですが、ルール1により禁じられています。
つまり、先手必勝とは限らない場合があるということです。

もう1つ、先手必勝でない(かも知れない)点があります。
それは「もし、後手も同じ戦法を取った場合、後手必勝パターンで先手に手を渡せるのでは?」という点です。
深入りしたいところですが、理屈はここまでとします。
次回はプログラミングを行うことにします。
--------------------
(*1)以降、隣合わないかどうかが一目でわかるよう、使用しないフィボナッチ数も0として記載しています。
(*2)参考文献(翻訳本)「不思議な数列フィボナッチの秘密(日経BP社)」

■第6回 山崩しゲーム/準備編(2016/12/11掲載,2017/01/04最終変更)
※この回(第6回)の説明に誤りがあることに後で気が付いたのですが、そのままにしてあります。訂正は次回(第7回)でおこないます。

石が積まれた山から、2人がルールに従って交互に石を取ってゆき、最後に石を取った方が勝ち(または負け)というゲームがあります。
一番有名なのは3つの山から石を取る「三山崩し」です。
三山崩しは排他論理和を使って最善手が計算できるので、マイコンとの対戦ゲームとしては最適です(*1)。

ここでは、3つの山ではなく、1つの山から石を取ってゆき「最後の石を取った方勝ち」というゲームです。
ただし、好きなだけ石を取って良ければ先手が最初にすべての石を取って先手必勝となってしまい、これではゲームになりません。
参考文献(*2)によれば、このゲームのルールは次の通りです。

ルール1-先手の第1手目では、全部の石を取ってはいけない。
ルール2-以降は、相手が直前に取った石の2倍までの石を取って良い。(たとえば、相手が3個取ったら自分は1~6個の範囲で好きな個数を取れる)

同じく、参考文献(*2)によれば、次の先手必勝法が存在します。

先手必勝法-現在の石の数をフィボナッチ数(*3)の和で表し、その中の一番小さなフィボナッチ数の石を取る

例えば石の数が20個の場合、3つのフィボナッチ数(13+5+2)の和で表せるので、その中の一番小さな数である2個取れば良いことになりま す。
実例として、石の山が15個でコンピュータが先手の場合のゲームの進行を見てみましょう。

・石の数15個(8+5+2)から、コンピュータが2個取る
・残った石の数13個から、人間はルール2により1~4個の範囲で取れるので、ここでは適当に4個取る
・残った石の数9個(5+3+1)から、コンピュータが1個取る
・残った石の数8個から、人間はルール2により1~2個の範囲で取れるので、ここでは適当に2個取る
・残った石の数6個(3+2+1)から、コンピュータが1個取る
・残った石の数5個から、人間はルール2により1~2個の範囲で取れるので、ここでは1個取る(ここらへんで、人間は負けそうなことに気が付き焦 り始めます)
・残った石の数4個(3+1)から、コンピュータが1個取る
・残った石の数3個から、人間はルール2により1~2個の範囲で取れるので、ここでは1個取る(すでに、人間は負けに気が付いています)
・残った石の数2個(2)から、コンピュータが2個取る、最後の石を取った方勝ちなのでコンピュータの勝ち


確かに、この例では先手のコンピュータは、石の数をフィボナッチ数の和で表した時の一番小さな数の石を取ることで勝ちました。
なお、ゲームとして飽きが来ないように毎回変化を持たせ、時には人間が勝つこともあるようにするため、次のように設計することとします。

設計1-最初の石の数は乱数で21~99の範囲とする。
設計2-人間に先手を持たせる
設計3-石の数が21以上のときは、コンピュータは乱数で取る石の数を決める
設計4-石の数が20以下になったら、コンピュータは必勝法(一番小さなフィボナッチ数を取る)に従い石を取る


次回は、この設計でプログラミングを行います。
このゲームは表示が少なくて済むので、マイコンキットZCPU1/K(液表示器2桁)を電池駆動で持ち歩いて遊べそうな気がします。
--------------------
(*1)排他論理和なので、理論上ロジックICでも計算できます。数十年前マイコン雑誌で読んだことがありますが詳しい内容は忘れました。
こういうときは伝家の宝刀、国立国会図書館の出番です。国立国会図書館の説明はコラム「色々」の「いざ、国立国会図書館へ!」を見てね。
(*2)参考文献(翻訳本)「不思議な数列フィボナッチの秘密(日経BP社)」
この本はフィボナッチ数列が、自然界や芸術など意外なところで現れることを紹介していて、山崩しゲーム必勝法はそのうちの1つです。
(*3)フィボナッチ数列{Fn}は、F1=F2=1,Fn=Fn-2+Fn-1で表せる数列 1,1,2,3,5,8,13,21,34,55,89,144,…で、フィボナッチ数はこの各項を意味します。

■第5回 ライフゲーム/動作編(2016/10/30掲載,2020/05/31最終変更)
前回でプログラミングは終了したので、動作検証してみまます。(説明の都合、個体をA、B、C…とします)

(1)個体が1個(結果:死滅する)
Aの周囲には個体がないため、2世代目(GEN=2)で死滅しました。

+0123456789
0..........
1..........
2..........
3...A......
4..........
5..........
6..........
7..........
8..........
9..........


(2)個体が2×2個(結果:変化せず)
各個体の周囲には3個の個体がある(Aの周囲ならBCDの個体、Bの周囲らACDの個体、…)ので生存しますが、発生(増殖)しません。
すなわち、個体の分布パターンは変化しません。

+0123456789
0..........
1..........
2..........
3...AB.....
4...CD.....
5..........
6..........
7..........
8..........
9..........


(3)個体が3×3個(結果:発生(増殖)する)
4隅のACGI以外は過密状態で死滅しますが、個体が無い座標(4,2)などの周囲の個体が3個の箇所があるで発生します。
世代が進むにつれて外に向かって発生(増殖)します。

+0123456789
0..........
1..........
2..........
3...ABC....
4...DEF....
5...GHI....
6..........
7..........
8..........
9..........


5世代目(GEN=5)のパターンは次の通りになりました。
個体数は初期値の9個から20個に増えています。

+0123456789
0..........
1....*.....
2...***....
3..*.*.*...
4.***.***..
5..*.*.*...
6...***....
7....*.....
8..........
9..........


一応うまく動作しているようです。
今回で、ライフゲームは終了とし、次回からはマイコンキットの16文字×2行の液晶ディスプレイで動作できるテーマにする予定です。
では、また。

■第4回 ライフゲーム/本編(2016/10/23掲載)
前回はライフゲームのルール説明と、境界部分の扱いについて説明しました。
今回はプログラムを作成し動作させてみます。

まず、変数を割り当ててゆきます。
配列 @( 0)~@( 99) 個体分布マップ(10×10のマス目、個体存在しない=0、個体存在する=1)
配列 @(100)~@(199) 周囲個体合計表(10×10のマス目、0~8の値をとる)
変数 X X座標(0~9)
変数 Y Y座標(0~9)
変数 G 世代数(1,2,3,…)
変数 S 作業変数(周囲個体合計)
変数 N 作業変数(1次元座標=Y*10+X)
変数 A,B 作業変数


ゲームのアルゴリズムは次の通りとします。
テップ1 個体分布マップを初期化(ゼロクリア)する
ステップ2 個体分布の初期値(XY座標)を聞き、個体分布マップに1を書込む(範囲外の座標入力でステップ3へ)
ステップ3 個体分布マップを画面表示
ステップ4 個体分布マップを元に周囲個体数を計算、周囲個体合計表に書込む
ステップ5 個体分布マップと周囲個体合計表にルールを適用し、個体分布マップを更新後、ステップ3に戻る


以上で設計終了です。
では、この設計通りプログラミングしていきます。

【プログラム4】ライフゲーム(#=3000で実行)
3000 (PROGRAM4)
3010 "LIFE GAME"

3020 (STEP1)
3030 N=0
3040 @(N)=0
3050 N=N+1
3060 #=(N<100)*3040

3100 (STEP2)
3110 "X=";
3120 X=?
3130 #=(X>9)*3200
3140 "Y=";
3150 Y=?
3160 #=(Y>9)*3200
3170 @(Y*10+X)=1
3180 #=3110

3200 (STEP3)
3210 G=0
3220 G=G+1
3230 "GEN=";
3240 ?=G
3250 Y=0
3260 X=0
3270 #=@(Y*10+X)=1*3300
3280 ".";
3290 #=3310
3300 "*";
3310 X=X+1
3320 #=(X<10)*3270
3330 Y=Y+1
3340 ""
3350 #=(Y<10)*3260
3360 ""

3400 (STEP4)
3410 Y=1
3420 X=1
3430 N=Y*10+X
3440 S=@(N-11)+@(N-10)+@(N-9)
3450 S=S+@(N-1)+@(N+1)+@(N+9)
3460 S=S+@(N+10)+@(N+11)
3470 @(N+100)=S
3480 X=X+1
3490 #=(X<9)*3430
3500 Y=Y+1
3510 #=(Y<9)*3420

3600 (STEP5)
3610 Y=1
3620 X=1
3630 N=Y*10+X
3640 A=@(N)
3650 B=@(N+100)
3660 #=(A=1)*(B=2)*3700
3670 #=(B=3)*3700
3680 @(N)=0
3690 #=3710
3700 @(N)=1
3710 X=X+1
3720 #=(X<9)*3630
3730 Y=Y+1
3740 #=(Y<9)*3620
3750 #=3220


ルールの適用部分は行番号の3660~3700です。
次回は、動作検証を兼ねていくつかのパターンを動作させみます。

■第3回 ライフゲーム/準備編(2016/10/09掲載,2020/05/31最終変更)
ゲームと呼んでいますが、内容は単純化された生態系のシミュレーションです。
有名なゲームなのでご存知の方も多いと思います。(*1)
配列と整数演算が使えるコンピュータであればプログラムできるため、マイクロBASICにはうってつけです。

なお、今回のテーマはマイコンキットの16文字×2行の液晶ディスプレイでは表示に限界があり断念しました。
多くの行を表示するため、マイコンキットにUSB-シリアルケーブルを介して入出力装置(ターミナル)を接続します。
ターミナルは、具体的にはターミナルソフトを動作させたパソコンです。

これから数回に渡ってプログラミングしてゆきます。
今回は準備編ということで仕様決めを行います。

まず、ルールの説明です。
10×10のマス目(*2)の大きな盤(将棋盤みたいなもの)に、初期値として適当な場所に数個の石(碁石みたいなもの)を置きます。
石は1つの生物(個体)で、次のルールに従って石の周囲の環境が良いと生存または発生し、悪いと死滅します。

ルール1-過疎状態(周囲の8個のマス目の石が0~1個)であれば、1世代後は死滅(石を取り除く)
ルール2-適正状態(周囲の8個のマス目の石が2~3個)であれば、1世代後は生存(石をそのままにしておく)
ルール3-過密状態(周囲の8個のマス目の石が4~8個)であれば、1世代後は死滅(石を取り除く)
ルール4-石が無い箇所の周囲8個のマス目の石が3個であれば、1世代後は発生(盤に石を置く)


なお、10×10のマス目のうち、周囲4辺(境界)のマス目は上下左右のいずれかが存在しません。
ここでは次のように境界を処理することにします。

境界処理-周囲4辺のマス目は初期状態のままで石が変化しないもの(固定)とする。すなわち、周囲4辺のマス目は世代更新処理を行わない。

この境界処理は解りにくいので、単純化された4×4のマス目(マス目番号0~F)で説明すると次のようになります。
元々の4×4のマス目は次の通りです。

0123
4567
89AB
CDEF


これに対し、実際に世代更新処理を行うマス目は、周囲4辺(境界)のマス目を除く2×2のマス目で、次の通りです。
....
.56.
.9A.
....


したがって、10×10のマス目の場合、世代更新処理を行う計算対象は中央の8×8のマス目のみです。

一次元配列しか持たないマイクロBASICでは、マス目は@(0)~@(99)で表現します。
したがって世代更新処理は、石のマス目を@(n)とした場合
@(n-11),@(n-10),@(n-9),@(n-1),@(n+1),@(n+9),@(n+10),@(n+11)
の和に対しルール1~ルール4を適用することになります。

今回はここまでとします。
ここまでのところ、アルゴリズムに特に問題はありません。
メモリ容量に少し不安があるところですが、こればかりは作ってみないと判りません。(*3)
--------------------
(*1)マーティン・ガードナーがScientific American誌のコラムで紹介(作者は別)したゲームです。
(*2) 最初16×16のマス目で動作させたのですが、処理時間がかかりすぎたため10×10に変更しました。
(*3)参考文献
「Make:Vol.04(オライリー・ジャパン)」数術師
「エンサイクロペディア・アスキーVolume3(アスキー出版)LIFE GAME

■第2回 πの計算/改定版(2016/09/22掲載,2016/10/23最終変更)(*1)
π(円周率)の計算は、次のライプニツの式で求めることができます。(*2)

π/4=1-(1/3)+(1/5)-(1/7)+(1/9)-(1/11)…

この計算式はオーバーフローの原因となる掛け算を使用しないため、マイクロBASICには最適です。
とりあえず、両辺を4倍してπの式にします。

π=4-(4/3)+(4/5)-(4/7)+(4/9)-(4/11)…

さらに、両辺に10000を掛けます。

10000π=(40000/1)-(40000/3)+(40000/5)-(40000/7)+(40000/9)-(40000/11)… (式1)

この式の右辺を見ると、計算途中で40000を超えることは無く、オーバーフロー(65535を超える)は起こりません。
しかも、計算結果がπの10000倍なので、小数点を4桁ずらせばそのままπの値になりそうです。

【プログラム2】πの計算(ライプニツの式)(#=2000で実行)
2000 (PROGRAM2)
2010 "PAI"
2020 A=1
2030 P=0
2040 P=P+(40000/A)
2050 ?=P
2060 A=A+2
2070 P=P-(40000/A)
2080 A=A+2
2090 ?=P;
2100 " : ";
2110 ?=A
2120 #=2040


このプログラムは永遠にループします。
計算結果の最初の数値はπの計算値、2番目の数値は(式1)の級数の分母1,3,5,7…の値です。
(式1)で約5000個の和まで加算したところでESCキーで停止させました。
結果は、(小数点を4桁ずらして読んで)3.1406と3.1409の間で振動しています。
真値3.141592…に対し一応3桁まで一致しました。
--------------------
(*1)計算経過がわかるようにプログラムを書き換え、改訂版として再掲載しています。
(*2)参考文献「世界大百科事典4(平凡社)」円周率

■第1回 ルート2の計算(2016/09/11掲載,2016/10/23最終変更)
最初のテーマはルート2の計算です。
ZCPU1/KのマイクロBASIC(以後、単にマイクロBASICと呼びます)が扱える数は0~65535の整数です。
2の平方根の計算とは、□×□=2となる□を求めることですが、整数しか扱えないマイクロBASICでは一工夫必要です。
ここでは、□×□=20000となる□を求め、最後に求めた数値□を2桁ずらして読むこととします。
具体的には□×□を1から順に計算し、計算結果が20000を超えた時点の□を2の平方根としています。
なお、行番号1070の#=50000は、今後他のプログラムと共存させるための工夫で数値計算とは関係ありません。

【プログラム1】ルート2の計算(#=1000で実行)
1000 (PROGRAM1)
1005 "ROOT 2"
1010 A=1
1020 #=(A*A>20000)*1050
1030 A=A+1
1040 #=1020
1050 ?=A;
1060 " ";
1070 #=50000


実行結果は、142となります。
2桁ずらして読むと1.42となり、真値1.4142…に対し一応2桁まで一致しました。
なお、行番号1020で、20000を30000および50000に書き換えると、それぞれルート3、ルート5の計算をします。

それにしても有効桁数が少なすぎます。
原因は、計算過程に2乗の計算(□×□)があり、計算結果が大きくなってオーバーフローするのを回避しなければならないためです。
次回は、2乗の計算を含まない円周率の計算を予定しています。(今度はもう少し有効桁数が増やせそうです)

■ごあいさつ(*3)(2016/09/11掲載,2020/06/01最終変更)
マイクロBASICを使って数値計算とゲームプログラミングに挑戦します。
ここでは、ZCPU1/K(E)のマイクロBASICを使用しますが、単純なプログラムなので一般のBASICへ容易に移植可能です。
置き換えの規則は、次のような感じです。(右側の表現であれば説明不要と思います)
--------------------------------------------------------
マイクロBASIC表記 ⇔ 一般のBASIC表記
--------------------------------------------------------
#=行番号     ⇔ GOTO 行番号
#=条件式*行番号 ⇔ IF 条件式 THEN 行番号
?=変数      ⇔ PRINT 変数
”文字列”     ⇔ PRINT”文字列”
(コメント文字列  ⇔ REM コメント文字列
@(引数)(*1)   ⇔ 変数名(引数)
--------------------------------------------------------


なお、本マイクロBASICは数式部の括弧は、配列の括弧と兼用で1レベルのみです。
また、演算子(+-*/)の優先順位はありません。
プログラムリストはトップページからダウンロードできます。(*2)
--------------------
(*1)1次元配列です。オリジナルのVTLとは表記が異なります。
(*2)ZCPU1/K(E)のマイクロBASICとターミナルソフトを使用した場合、プログラム(テキストファイル)のセーブ、ロードができます。
ターミナルソフト上で、チルダ(~)をキー入力し、以降メッセージに従ってください。
(*3)元々タイトルは無かったのですが、目次を追加したため、便宜上「こあいさつ」とタイトルを付けました。

このソフトウェアに関するご意見・ご質問等をお待ちしています。
to@takami.com  (アドレスは半角で入力ください)

[トップページに戻る]

マイクロBASICによる数値計算とゲーム