目次
はじめに
これから使うコンピュータのプログラム一覧のなかに、下図のような BASIC256 アイコンがあればそのアイコンをクリックするとBASIC256の起動画面がでる。
もしプログラム一覧のなかにBASIC256がなければ、インストールする必要がある。
BASIC-256 のダウンロードとインストールは、この sourceforge の kidbasic から行う。
kid basic は、子供用のプログラム言語 BASIC を意味する。
おもちゃのピアノのように、ソースコードを楽譜のようにしてコンピューティング世界で遊ぶことができる。
![Golton Box](http://rosettacode.org/mw/images/8/8b/Galton_box_BASIC-256.g
BASIC256 起動
プログラム エディター テキスト出力
+---------------------+ +--------------------+
| | | |
| | | |
| | | |
| | | |
| | +--------------------+
| | グラフィック出力
| | +--------------------+
| | | |
| | | |
| | | |
| | | |
+---------------------+ +--------------------+
BASIC-256 を起動すると、このような窓が開く。
プログラム エディターの窓には、ソースコードを入力する。
メニューの Run ボタンを押すと、プログラムは実行される。
プログラムを実行すると、テキストの出力は右上に、グラフィックの出力は右下に表示される。文字、画像どちらの出力もコピーあるいは印刷することができる。テキスト出力の窓へは、Windowsクリップボードからペースト、貼り付けも可能。
もし、プログラムにエラーをBASIC-256が発見すると、エラーの内容は赤字でテキスト出力される。
粘土のタブレット
バビロニア 粘土タブレット メソポタミアで出土した。
1800 - 1600 BC 頃のもの。
メソポタミアとは、チグリス、ユーフラテス川にはさまれた地域のことで、ギリシア語起源。
メソポタミアの南部をバビロニア、北部をアッシリア、またバビロニアの最南部ペルシャ湾に面した地域をシュメールと呼ぶ。シュメールは世界最古の文明のひとつといわれている。
この粘土タブレットには、60進数で数が刻まれている。
まんなかの直線に刻まれた数、10進数で表記すると、
1 ; 24 , 51 , 10
セミコロンの左は、整数部、右は小数部である。
したがって、
24/60 = 0.4
51/3600 = 0.0141667
10/216000 = 4.62963e-5
1 + 0.4 + 0.0141667 + 4.62963e-5 = 1.414213
百万分の一の桁まで √2 を正確に計算して刻んだ粘土タブレットだということがわかる!
このように数学問題を式を刻んだ粘土版が、バビロニアの学校で使用されていたことがわかっている。
これを、現代のコンピュータで計算してみよう。
BAISC 256 を起動して、コードを入力し、実行(Run)させる。
BASIC256 コードの書き方
1. 整数列の出力
変数と値
i=1
数、文字などに名前をつけて保存(変数名)する。
上式のi=1
は、変数i
に整数値 1 を入れる。
変数i
の古い値は消滅し、新しい値になる。
j=2*i-1
まず
=
の右辺の式が計算される。変数i
の値が2倍され、その値から1引かれる。その結果が変数>j
の新しい値になる。
「i=1」は、i
の値を1
にする命令。
「j=2*i-1」命令の右辺にある、*
はかけ算、-
は引き算。
2+1 ... 3
1-2 ... -1
2*3.14 ... 6.28
1/3 ... 0.333333333333 有効桁数12
1\3 ... 0 整数除算
1%3 ... 1 余り
定数の書き方
整数
1089
-30
0
10進数
-273.15
2.71828
pi 円周率 3.14159265359
科学表記
3.844e8 地球から月までの距離 384,400km=384,400,000m
2.99792458e8 光速度 299,792,458m/s
練習問題 月面の光が地球に届くまでの秒数
print 3.844e8
e2m=3.844e8
sol=2.99792458e8
print sol
print e2m/sol
BASICコードの実行
命令は、先頭行から次の行へと順番に実行される。
BASICコードの実行が始まった瞬間は、i
やj
変数にはなにがはいっているかわからない。
i=1
やj=2*i-1
が実行されてはじめて、変数の値が設定される。
命令は先頭から順番に実行されるが、いくつか例外がある。
それを制御コードという。詳細は、あとで解説する。
- 繰り返し (for ... next)
- 分岐 (if ... then ... else ...)
- ジャンプ (goto ...)
- サブプログラム (gosub ...) 関数 (call ...)
- エンド (end)
反復
回数を決めて、その回数だけ繰り返す。
for ... next (for next ループともいう)
テキスト出力
print i (変数i
の値をテキスト窓に出力する)
グラフィック出力
次の「2. 直線と点を描く」で解説する。
音声出力
say "Charge!"
音楽再生
サンプル
sound { 392, 375, 523, 375, 659, 375, 784, 250, 659 ,250, 784, 250}
BASIC 256 の解説書より
# littlefuge.kbs
# Music by J.S.Bach - XVIII Fuge in G moll.
tempo = 100 # beats per minute
milimin = 1000 * 60 # miliseconds in a minute
q = milimin / tempo # quarter note is a beat
h = q * 2 # half note (2 quarters)
e = q / 2 # eight note (1/2 quarter)
s = q / 4 # sixteenth note (1/4 quarter)
de = e + s # dotted eight - eight + 16th
dq = q + e # doted quarter - quarter + eight
sound {392, q, 587, q, 466, dq, 440, e, 392, e, 466, e, 440, e, 392, e, 370, e, 440, e, 294, q, 392, e, 294, e, 440, e, 294, e, 466, e, 440, s, 392, s, 440, e, 294, e, 392, e, 294, s, 392, s, 440, e, 294, s, 440, s, 466, e, 440, s, 392, s, 440, s, 294, s}
練習 整数列の出力
- 1,2,3,4,5,6,7,8,9,10
i
の値を1からはじめ、1ずつ増加させる。i
が10になったら
for i=1 to 10
print i
next i
横に並べる。
for i=1 to 10
print i;" ";
next i
- 1,3,5,7,9,11,13,15,17,19
奇数を1からはじめ、最初の10個をプリントする。
for i=1 to 10
j=2*i-1
print i;" ";j
next i
TAB を使う。
for i=1 to 10
j=2*i-1
print i;chr(9);j
next i
練習問題
1. 次の数列をできるかぎり正確に計算してみる。
1 1 1 1
A = 1 - - + - - - + - - ...
3 5 7 9
Aを4倍するとよく知られた数になる。それは何か?
次の100番目の奇数までを分母にした数列Aの和を計算するコードを参考にし、項の数 i
を大きくして計算してみよう。
変数cを1,-1と切り替えながら、分数の和を求めている。
a=0
c=-1
for i= 1 to 100
b=2*i-1
c=-c
a=a+c/b
next i
print a
このコードを BASIC 256 にペーストして実行した結果は、次のようになった。
この結果を、4倍するとどうなるだろうか。さらに、奇数を1000番目まで増やして数列の和を計算するとどうなるだろうか。やってみよう。
同じ計算を JavaScript コード で実行するには、
for 文の書き方、文法が違うが、構造は似ている。BASICがわかれば、JavaScriptも書ける。
変数名もコードのはじめにそれぞれ定義している。
出力は、webにhtmlコードを書き出している。
BASIC は 100個の逆数和まで計算したが、下のJavaScriptは、1万まで計算した。
var i, a, b, c;
a = 0;
c = -1;
for (i = 1; i <= 10000; i += 1) {
b = 2*i-1
c = -c
a = a+c/b
}
document.write(a + '<br>');
** 実行方法 **
-
JavaScript コードを メモ帳 (notepad) などで書き、ファイルとして適当な場所、たとえばデスクトップに保存する。
-
Chrome の新しいタブを開き、
Ctrl + Shift + I
を押し、JavaScript の開発ツールのコンソール(Console) を開く。 -
JavaScript のソースコードを コピー (copy) し、Chrome の JavaScript Cosole に ペースト (paste) する。
-
Enterキーを押す。
-
実行結果が、Web画面として表示される。
-
もし、赤字でエラーが表示されたときは、ソースコードを見直し修正して、再度コピペ。
-
a*4とタイプすれば、a を計算したことの意味がわかる。
BASICでも10000まで計算して比較してみよう。また、もっと大きな数まで計算して比較するとどうだろうか。
グラフィックを追加
clg
a=0
c=-1
for i= 1 to 10000
b=2*i-1
c=-c
a=a+c/b
plot 1.1*i,2100*a -1500
next i
print a
2. 次の4のべき乗を分母にした数列の和から3を作る。
1 1 1 1 1 1
- + - + - + - + - ... = -
4 2 3 4 5 3
4 4 4 4
参考リンク
したがって、初項が 1/4 で 公比 1/4 の等比数列の和は、
(1/4)/(1-(1/4)) = (1/4)/(3/4)
コーンを切る曲線
上図は、Wikipedia より引用。
コーン(円錐)を切断する切り方により、円、楕円、放物線、双曲線の4種類の断面があらわれる。これら4つの曲線は円錐曲線とよばれる。
実際の惑星、月、小惑星などについては、NASAのサイトが詳しいが天文学の知識がないと理解できないのが大部分である。
ただ、地球のまわりを回っている月の運動が完全な円でない程度は、NASAのこのサイト(太陽系を探索)をみれば、地球からの距離が変化していることからわかる。
放物線 パラボラ(Parabola)
上図は、Wikipedia より。
高さ y0 の位置から物体を上方へ角度 θ 、速度 v で発射したあとの物体の軌跡を描く。
ハレー彗星
NASAによる、太陽系のなかのハレー彗星の軌道を描いたアニメーション。
太陽系のなかにある天体の運動を理解する研究ための研究はニュートンの時代にはじまった。地球と月のような2体問題は、微分方程式として解くことができる。3次元空間の粒子の運動として理想化すれば、ひとつの粒子を固定して考えるともう一つの粒子が描く軌道は、円、楕円、放物線、双曲線などの円錐曲線あるいは直線となることが証明されている。
しかし、n が 3以上の n体問題はどうなるのだろうか。それはここでは触
曲線を点の軌跡として描く
2次元の平面内で座標(x,y)
が与えられたとして、その位置に点を描く。その前に色をcolor
で指定する。
コンピュータの画面座標は、左上が原点 (0,0) になっている。x軸は原点から水平に右へ、y軸は原点から下へ垂直に伸びている。
初期座標を(h,k)
とし、色を red
として、グラフィック画面の座標(x,y)
に点を打つコードは次のようになる。
color red
x=h
y=k
plot x,y
円曲線
点の軌跡として、円周を点の集合で描く。
円の中心座標を(h,k)
とする。
円を描く軌跡の座標は、次のようにして決まることを思い出す。
x = h + r × cos(θ)
y = k + r × sin(θ)
ここで、
r は、円の半径。
θ は、角度( 0 ~ 2π )。
次のコードのように初期値(中心と半径r)を与え、角度を0~2πまで変化させて点の集合が円になるかどうかたしかめる。色はブルーで、中心点と円周上の点を描く。
for theta=0 to 2*pi step 0.1
により、角度は 0.1 ラジアン単位で0から2πまで増加させている。角度θは、変数名theta
とした。
clg
color blue
h=100
k=100
r=100
plot h,k
for theta=0 to 2*pi step 0.1
x=h+r*cos(theta)
y=k+r*sin(theta)
plot x,y
next theta
end
clg は、グラフィック画面を消去するために、先頭行に置いてある。下図で、円周上の点は何個あるか?
step 0.01
とさらに角度を10分の1細かくすると次のようになる。
練習問題
-
for theta=0 to pi step 0.01
と角度を0~πまでにするとどうなるか。 -
さらに、
y=k-r*sin(theta)
とy座標の計算式を変更するとどうなるだろう。その理由は? -
さらに角度の刻みを細かくすると、見た目は変化するだろうか。
ディスプレイの解像度とも関係している。
JavaScript の lineTo(x,y) で正多角形を描く
JavaScript code
circle001.js
var ctx, wid, hei;
wid = 500;
hei = 500;
function drawCircle() {
var step = 2*Math.PI/20;
var h = 150;
var k = 150;
var r = 100;
ctx.beginPath();
for(var theta=0; theta < 2*Math.PI; theta+=step)
{ var x = h + r*Math.cos(theta);
var y = k - r*Math.sin(theta);
ctx.lineTo(x,y);
}
ctx.closePath();
ctx.stroke();
}
function createCanvas(w,h) {
var canvas = document.createElement("canvas");
canvas.width = w; canvas.height = h;
canvas.id = "canvas";
ctx = canvas.getContext("2d");
ctx.fillStyle = "white"; ctx.fillRect(0,0,wid,hei);
document.body.appendChild(canvas);
}
function initCircle() {
createCanvas(wid,hei);
drawCircle();
}
html code
circle001.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">
<title>Draw a Circle into Canvas element</title>
<script src="circle001.js" type='text/javascript'>
</script>
</head>
<body onload="initCircle()">
</body>
</html>
練習問題
- この多角形の辺はいくつか?
- 辺の数を決めているのは、どの変数か? ヒント:
var step = 2*Math.PI/20;
- コードを書いて、正三角形、正方形、正五角形、正六角形などを描く。
- JavaScript だけでなく、BASIC でも正多角形を描くコードを書く。
次のサンプルコードの3行目の除数6は、正六角形を書くため。この除数を変化させてみるとどうなるだろうか。
clg
color blue
stp=2*pi/6
h=150
k=150
r=150
plot h,k
ox=h+r:oy=k
for theta=0 to 2*pi step stp
x=h+r*cos(theta)
y=k+r*sin(theta)
line ox,oy,x,y
ox=x: oy=y
next theta
end
sin, cos
直角3角形
sin, cos を定義する
sin A の値は、角 A の対辺 c を 一番長い辺 a で割ったもの。
sin A = c / a
cos A の値は、角 A の隣接辺 b を 一番長い辺 a で割ったもの。
cos A = b / a
練習問題 直角3角形を poly で描く。
clg
color blue,green
poly {{50,200}, {250,200}, {250,100} }
color blue
font "Tahoma",12,75
text 70,180,"A"
text 150,120,"a"
text 150,195,"b"
text 250,145,"c"
バイブレーションと音楽
音楽は振動からできている。
「オーディオ周波数 - Wikipedia」などのサイトを参考に、人間が聞き取ることができる音の周波数をたしかめてみる。
BASIC 256 のチュートリアルにあるバッハのフーガを演奏するコードも、振動と持続時間の組み合わせである。
では、この振動の周波数のもとになっているものは何だろうか。
# littlefuge.kbs
# Music by J.S.Bach - XVIII Fuge in G moll.
tempo = 100 # beats per minute
milimin = 1000 * 60 # miliseconds in a minute
q = milimin / tempo # quarter note is a beat
h = q * 2 # half note (2 quarters)
e = q / 2 # eight note (1/2 quarter)
s = q / 4 # sixteenth note (1/4 quarter)
de = e + s # dotted eight - eight + 16th
dq = q + e # doted quarter - quarter + eight
sound {392, q, 587, q, 466, dq, 440, e, 392, e, 466, e, 440, e, 392, e, 370, e, 440, e, 294, q, 392, e, 294, e, 440, e, 294, e, 466, e, 440, s, 392, s, 440, e, 294, e, 392, e, 294, s, 392, s, 440, e, 294, s, 440, s, 466, e, 440, s, 392, s, 440, s, 294, s}
ここでは、十二平均律による音階をもちいている。
sound 関数による、周波数と時間をペアにしたリストで、音階を表現できる。
sound {440,500, 466,500, 494,500, 523,500, 554,500, 587,500, 622,500, 659,500, 698,500, 740,500, 784,500, 831,500, 880,500}
正弦波 sin A
はじめに 直角3角形を考える。角度 A を定め、各辺の長さを a,b,c とし、辺 b と c の間の角度を 90° とする。
角度 A と、sin A, cos A の値について、 角度 A を 0°から90° まで変化させたときのグラフを描いてみる。
これらの曲線を、それぞれ サイン ウェーブ(カーブ) および コサイン カーブと呼ぶ。
角度が0から90°までのサイン・ウェーブの波形は次のようになる。
図. sin A
sin A, cos A は、直角3角形の大きさに関係なく、角度 A だけで決まる。
上の図を描くためのコードは次のようになる。実行してみる。
clg
color black,white
rect 50,50,200,200
text 50,260,"0"
text 250,250,"90"
penwidth 3
color red
for i=0 to pi/2 step 0.05
x=50 + int(i*200*2/pi)
y=250 - int(sin(i) * 200)
plot x,y
print x;" ";y
next i
end
練習問題 Y軸を修正する
上のコードで曲線を描くと、Y軸の上限値 1 が抜けている。
修正後
上のようにY軸に上限値「1」を書き入れるように、コードを修正する。
練習問題 cos A について、「図. sin A」と同様のグラフを描く。
正弦波 sin A と同様に、余弦 cos A の波形も描く。
正弦波 sin A の曲線は、0°~90°で上昇するが、その後はどうなるだろうか?
数学では A を直角3角形の「角度」という概念から切り離して、単に数としてとりあつかうことにする。
そこで sin と cos のグラフを描き、sin A や cos A の値は、グラフの曲線から定義されたものとしてあつかうことになる。
clg
line 0,150, 280,150 # X axis
text 290,140,"X"
line 0,20,0,300 # Y axis
text 0,0,"Y"
text 0,150,"O"
color red
for x = 0 to 4 * 3.14159 step 0.05
y = sin(x)
plot int(20*x), 150 - int(30*y)
next x
color green
for x = 0 to 4 * 3.14159 step 0.05
y = cos(x)
plot int(20*x), 150 - int(30*y)
next x
end
練習問題 上のsin, cos のグラフで赤が sin、緑が cos というのを分かりやすく文字で書き込む
ピタゴラスの定理
直角3角形の辺 a,b,c について次の関係式が成立する。
a 2 = b 2 + c 2 ... (1)
両辺を a 2 で割る。すると (2) が成立することがわかる。
(b/a) 2 + (c/a) 2 = 1 ... (2)
直角3角形の辺の比を、sin, cos に書き直すと (3) になる。
(sin A) 2 + (cos A) 2 = 1 ... (3)
グラフィック 基本形
海外の信号機
clg
color black
rect 100,50,100,200
color darkred
circle 150,100,20
color darkyellow
circle 150,150,20
color green
circle 150,200,20
say "Green light. You may go."
clg
グラフィック画面クリア
rect x1,y1,x2,y2
直方体
座標 左上 x1,y1
右下 x2,y2
circle x,y,r
円
中心 x,y
半径 r
say
音声
練習 日本の信号機をつくる
3角形
clg
color black
line 150, 100, 100, 200
line 100, 200, 200, 200
line 200, 200, 150, 100
立方体
2点をむすぶ直線 (x1,y1) - (x2,y2)
line x1,y1,x2,y2
clg
# 後ろの四角形
line 150, 150, 150, 250
line 150, 250, 250, 250
line 250, 250, 250, 150
line 250, 150, 150, 150
# 前の四角形
line 100, 100, 100, 200
line 100, 200, 200, 200
line 200, 200, 200, 100
line 200, 100, 100, 100
# 頂点をむすぶ
line 100, 100, 150, 150
line 100, 200, 150, 250
line 200, 200, 250, 250
練習 立方体を完成させる
線の幅
なにも指定しなければ、1 ドットの幅。
例: 7ドット
penwidth 7
点
オレンジ色の点
color orange
plot 100,100
plot は、1ドットの大きさなので、見えにくい。
ドットの大きさは、penwidth で変更できる。
penwidth 10
plot 150,100
ポリゴン
clg
color red
poly { 150, 100, 200, 150, 175, 150, 175, 200, 125, 200, 125, 150, 100, 150 }
ペン色、ブラシ色の指定
次の例題コードで図形に色を付ける方法を解説する。
円形の縁を5ドット幅グリーンにし、内側をレッドで塗ることにする。このために、
まず、ペン先の太さを penwidth 5
で5ドットに設定する。
color green,red
は 、縁をグリーンにし内部をレッドに色指定する。
clg
color rgb(128,128,128)
rect 0,0,graphwidth, graphheight
penwidth 5
color green,red
circle 100,100,50
penwidth 1
color rgb(255,160,160)
circle 100,100,25
実行結果は、次のようになる。
ペン先を1ドットにもどし、薄い赤色で円を描いているのがおわりの3行である。色の指定は、RGBの値を color rgb(255,160,160)
により直接あたえている。
練習問題 サルと人間の手足
- チンパンジー
- マダガスカル・キツネザル
- オナガザル
- 人間
前のスクリーンに示す図中の a,b,c,d は、1~4のどれにあたるか? 図はアンドレ・ルロワ=グーラン『世界の根源』ちくま学芸文庫より。
練習問題 月の満ち欠け
国立天文台の暦Wiki
のページを参考にして、朔(新月)、上弦、望(満月)、下弦の月 を BASIC のコードで書く。
Subroutine
作業を分割し、コードを読み易く
subroutine サブルーティン
はじめの一歩
コードをメインとサブルーティンに分割する。
メインのコードは、オレンジ色で半径10の大きさのボール (circle x,y,10) をあらかじめ縦(100)、横(100)の長さをきめた2次元平面の中で初速度(xspeed,yspeed)を与えて投げる。
そのボールの運動の軌跡を描く。ボールをサブルーティンを使って円 (circle x,y,10)で描く。色は、color orange にする。
ただし、2次元平面の境界線に当たる(if x>width or x<0)と xspeedとyspeedを反転(-1を速度に×)させる。
また、ボールが外界から受ける摩擦抵抗はゼロとする。
global グローバルにつかう変数名の定義
global x,y, ...
subroutine drawBall()
ボールの位置を計算し、オレンジ色(color orange
)でボールを描き(circle x,y,10
)、少し時間待ち(pause 0.01
)(0.01秒)をして、ボールをホワイト色(color white
)で描く。
これを無限に繰り返す(loop: 「繰り返す文」 goto loop
)。
最初のコード
global x,y,xspeed,yspeed,width,height
x=100
y=100
xspeed=1
yspeed=3
width=300
height=300
clg
loop:
call drawBall()
pause 0.01
color white
circle x,y,10
goto loop
end
subroutine drawBall()
x=x+xspeed
y=y+yspeed
if (x>width) or (x<0) then xspeed=xspeed * -1
if (y>height) or (y<0) then yspeed=yspeed * -1
color orange
circle x,y,10
end subroutine
練習1 ボールの軌跡を背景と同色にして消す
ヒント
clg のあとに次のコードを挿入する。灰色(color grey
)の四角形(`rect 0,0,300,300)を描く。
color grey
rect 0,0,300,300
pause 0.01 の次の行に color grey
を挿入する。
練習2 ボールのはじめの位置を input 命令で入力する
input "x= ", x
input "y= ", y
練習3 インタラクティブなコード
マウスでボールを操作する。
mousex, mousey は、それぞれ現在のマウスの座標を返す関数になる。そのマウス関数を使った次の2行をy=y+yspeed
の次に追加するとどうなるか。
if (x>mousex) then x=mousex
if (y>mousey) then y=mousey
マウスを左上から右下、次に右下から左上に移動させてみよう。ボールはどんな風に動いただろうか?
マウスを動かし、ボールの右にマウスポインタがあるとボールはゆっくりポインタを追いかける。しかし、ボールの左にマウスポインタをもっていけば、すぐにボールは追い付く。これはif
文の判定条件を>
にしているためだ。Y座標、すなわちボールの上下運動も同じようにy>mousey
で判定しているために同様になる。
練習問題 面白い計算?
次のコードは、数字 1 が連続する数についてけた数が増やしながら、かけ算をした結果をグラフィック画面に表示する。
color grey
rect 0,0,graphwidth,graphheight
color green
x=1
y=1
for i=1 to 5
z=x*y
font "Courier",18,100
text 10,100,string(z)
pause 3
color grey
text 10,100,string(z)
color green
x=x*10+1
y=y*10+1
next i
end
このコードを数字 1 がいくつ並ぶとその結果がどうなるかを表示するようにサブルーティンを使って編集したひとつの例が次のコードである。
color grey
rect 0,0,graphwidth,graphheight
color green
x=1
y=1
for i=1 to 5
z=x*y
call displayTextAt(20,10,x)
call displayTextAt(10,100,z)
x=x*10+1
y=y*10+1
next i
end
subroutine displayTextAt(xc,yc,z)
font "Courier",18,100
text xc,yc,string(z)
pause 3
color grey
text xc,yc,string(z)
color green
end subroutine
これらをBASIC256で実行してみる。
このコードを改良してみよう。
フォースを侮るな ー ダース・ベイダー
-- Wikipedia
ボールとパドルでゲーム
BASIC 256 をインストールしたディレクトリーの下の階層に sprites と名前がつけられたディレクトリーがある。そのなかにある bounce.kbs で遊んでみよう。
もとのプログラム bounce.kbs の速度を遅くしたコードを下に載せる。pause 0.1 により遅らせている。
# ball bounce program
# 2010-06-13 j.m.reneau
# 2019-10-21 ms
print "use mouse to bounce ball on paddle."
color black
rect 0,0,300,300
dx = 1
dy = 1
spritedim 2
spriteload 0, "ball.png"
spriteplace 0,10,10
spriteshow 0
spriteload 1, "paddle"
spriteplace 1,150,270
spriteshow 1
while spritey(0) < 295
pause 0.01
spriteplace 1, mousex, 270
if spritex(0) < 5 or spritex(0) > 295 then dx = dx * -1
if spritey(0) < 5 then dy = dy * -1
spritemove 0, dx, dy
if spritecollide(0,1) then
dx = (dx + (spritex(1)-spritex(0)) * .05) * -1
dy = dy * -1.05
end if
end while
print "you missed."
この bounce.kbs を動かすためには、2つの画像が必要になる。ボール ball.png とバドル paddleの画像だ。これらも basic256.org からのコピーを下に貼りつけておく。
古典的なゲームの仕組み
質問
- ゲームで遊んだことがある?
- 好きなゲームは?名前をいくつかあげて
- 記憶に残ってる子供のころ遊んで面白かったゲームは?
- この付近に、古典的ゲームに登場したモノがいる、それは何か?
どのキーが押されたか?
次のコードは、押されたキーに対応する数値を表示する。シフトキーやコントロールキーを押しても数値が表示される。このことから、表示される数値は単純なアスキーコードだけではないことが実行すればわかる。
#press any keys
loop:
pause 1
a = key
print a+" "+chr(a)
goto loop
key
関数でどのキーが押されたか?を数値により判定することができる。
キーと数値の一覧表
練習問題 キーと数の関係
英字、数字、記号、その他の特殊キー (ESC, Shift, Enter, ...)を押して、キーと表示される数の関係をしらべてみる。
アスキー コード
練習問題 Q を押すまで続ける
# readkey.kbs
print "press a key - Q to quit"
do
k = key
if k <> 0 then
if k >=32 and k <= 127 then
print chr(k) + "=";
end if
print k
end if
until k = asc("Q")
end
このコードを実行したあと、どのキーも押さなければ 関数 key が ゼロ となることを if k <> 0 then ...
文によって実現させている。
練習問題 何秒でキーを押せるか?
# keymsec.kbs
# get the code for a random character from A-Z
c = asc("A") + int(rand*26)
# display the letter (from the numeric code)
print "press '" + chr(c) + "'"
time = msec # get the start time
do # wait for the key
k = key
until k = c
time = msec - time # calculate how long (in ms)
print "it took you " + (time/1000) + " seconds to find that letter."
キーでボールを動かす
# keymoveball.kbs
# move a ball on the screen with the keyboard
print "use i for up, j for left, k for right, m for down, q to quit"
fastgraphics
clg
# position of the ball
# start in the center of the screen
x = graphwidth /2
y = graphheight / 2
r = 20 # size of the ball (radius)
# draw the ball initially on the screen
call drawball(x, y, r)
# loop and wait for the user to press a key
while true
k = key
if k = asc("I") then
y = y - r
if y < r then y = graphheight - r
call drawball(x, y, r)
end if
if k = asc("J") then
x = x - r
if x < r then x = graphwidth - r
call drawball(x, y, r)
end if
if k = asc("K") then
x = x + r
if x > graphwidth - r then x = r
call drawball(x, y, r)
end if
if k = asc("M") then
y = y + r
if y > graphheight - r then y = r
call drawball(x, y, r)
end if
if k = asc("Q") then exit while
end while
print "all done."
end
subroutine drawball(ballx, bally, ballr)
clg white
color red
circle ballx, bally, ballr
color rgb(255,100,100)
circle ballx+.25*ballr, bally+.25*ballr,ballr*.50
color rgb(255,150,150)
circle ballx+.25*ballr, bally+.25*ballr,ballr*.30
color rgb(255,200,200)
circle ballx+.25*ballr, bally+.25*ballr,ballr*.10
refresh
end subroutine
練習問題 矢印キーでボール動かす
上のコードのなかで、キーを判定する部分を次のように変更する。
k = key
if k = 16777235 then
y = y - r
if y < r then y = graphheight - r
call drawball(x, y, r)
end if
if k = 16777234 then
x = x - r
if x < r then x = graphwidth - r
call drawball(x, y, r)
end if
if k = 16777236 then
x = x + r
if x > graphwidth - r then x = r
call drawball(x, y, r)
end if
if k = 16777237 then
y = y + r
もう少し文字コードについて
この BASIC 256 では、漢字は使えない。英数記号のアスキー文字だけである。
そこで、マイクロソフトのワードを使う。ワードを起動し、白紙のページを用意する。
文字コードのなかで、アラビア文字や漢字やハングル文字などを使える Unicode(ユニコード) 体系がある。このユニコードで漢字を入力してみよう。
例として、「毳」を入力してみよう。布の生地表面にできる「けば」である。
これを入力するには、毳のユニコードである「6BF3」とタイプして ALTキーを押しながら、X キーを押す。すると、6BF3 が変換されて毳に置換されるはずである。
ユニコードの表は、Unicode 12.1 Character Code Charts にある。日本の漢字は、この表の CJK Unified Ideographs (Han) 辺りを探すと見つけることができる。
練習問題 自分の姓をユニコードで覚える
上のリンク先の表から、自分の姓を探して、ユニコードで入力し ALT + X で変換する。
練習問題 絵文字(emoji) など、その他のユニコード
ユニコードに収録されている文字は全部でいくつくらいあるのだろうか?
マウスで操作するマインスイーパー
マウスを動かし、左クリックと右クリックで画面を操作する。
そのためにマウスの 左・右・中 ボタンがクリックされたとき、その値を検出する関数 mouseb を利用する。
ボタン操作 mouseb値
クリックなし 0
左クリック 1
右クリック 2
中クリック 3
mouseb のコード例
マウスポインターを Graphics Output 窓に移動させ、ボタンをクリックすれば Text Output 窓に mouseb の値が表示される。
loop:
m=mouseb
print m;
goto loop
マインスイーパーの例
次のコードは、上のロゼッタコード掲載のものに若干の修正を加えている。理由は、BASIC-256 version 1.99.99.67(2016-09-08) - built with QT 5.5.0 でのコンパイル時のエラーを無くすため。修正点は、主として color 文。
N = 6 : M = 5 : H = 25 : P = 0.2
fastgraphics
graphsize N*H,(M+1)*H
font "Arial",H/2+1,75
dim f(N,M) fill 0# 1 open, 2 mine, 4 expected mine
dim s(N,M) fill 0# count of mines in a neighborhood
trian1 = {1,1,H-1,1,H-1,H-1} : trian2 = {1,1,1,H-1,H-1,H-1}
mine = {2,2, H/2,H/2-2, H-2,2, H/2+2,H/2, H-2,H-2, H/2,H/2+2, 2,H-2, H/2-2,H/2}
flag = {H/2-1,3, H/2+1,3, H-4,H/5, H/2+1,H*2/5, H/2+1,H*0.9-2, H*0.8,H-2, H*0.2,H-2, H/2-1,H*0.9-2}
mines = int(N*M*P) : k = mines : act = 0
while k>0
i = int(rand*N) : j = int(rand*M)
if not f[i,j] then
f[i,j] = 2 : k = k - 1 # set mine
s[i,j] = s[i,j] + 1 : gosub adj # count it
end if
end while
togo = M*N-mines : over = 0 : act = 1
gosub redraw
while not over
clickclear
while not clickb
pause 0.01
end while
i = int(clickx/H) : j = int(clicky/H)
if i<N and j<M then
if clickb=1 then
if not (f[i,j]&4) then ai = i : aj = j : gosub opencell
if not s[i,j] then gosub adj
else
if not (f[i,j]&1) then
if f[i,j]&4 then mines = mines+1
if not (f[i,j]&4) then mines = mines-1
f[i,j] = (f[i,j]&~4)|(~f[i,j]&4)
end if
end if
if not (togo or mines) then over = 1
gosub redraw
end if
end while
imgsave "Minesweeper_game_BASIC-256.png", "PNG"
end
redraw:
for i = 0 to N-1
for j = 0 to M-1
if over=-1 and f[i,j]&2 then f[i,j] = f[i,j]|1
gosub drawcell
next j
next i
# Counter
color rgb(32,32,32) : rect 0,M*H,N*H,H
color white : x = 5 : y = M*H+H*0.05
if not over then text x,y,"Mines: " + mines
if over=1 then text x,y,"You won!"
if over=-1 then text x,y,"You lost"
refresh
return
drawcell:
color darkgrey
rect i*H,j*H,H,H
if f[i,j]&1=0 then # closed
color black : stamp i*H,j*H,trian1
color white : stamp i*H,j*H,trian2
color grey : rect i*H+2,j*H+2,H-4,H-4
if f[i,j]&4 then color blue : stamp i*H,j*H,flag
else
color rgb(192,192,192) : rect i*H+1,j*H+1,H-2,H-2
# Draw
if f[i,j]&2 then # mine
if not (f[i,j]&4) then color red
if f[i,j]&4 then color darkgreen
circle i*H+H/2,j*H+H/2,H/5 : stamp i*H,j*H,mine
else
if s[i,j] then color rgb(32,32,32) : text i*H+H/3,j*H+1,s[i,j]
end if
end if
return
adj:
aj = j-1
if j and i then ai = i-1 : gosub adjact
if j then ai = i : gosub adjact
if j and i<N-1 then ai = i+1 : gosub adjact
aj = j
if i then ai = i-1 : gosub adjact
if i<N-1 then ai = i+1 : gosub adjact
aj = j+1
if j<M-1 and i then ai = i-1 : gosub adjact
if j<M-1 then ai = i : gosub adjact
if j<M-1 and i<N-1 then ai = i+1 : gosub adjact
return
adjact:
if not act then s[ai,aj] = s[ai,aj]+1 : return
if act then gosub opencell : return
opencell:
if not (f[ai,aj]&1) then
f[ai,aj] = f[ai,aj]|1
togo = togo-1
end if
if f[ai,aj]&2 then over = -1
return
練習問題 このマインスイーパーの遊び方を説明する
15 パズルゲーム
Rosetta Code から、Liberty BASIC
のコードをもとにBASIC 256 で動くように書き換えたのが、下のコード。これは不完全なコード。
遊び方
ゲームをはじめると、次のようなテキスト画面がでる。ゲームのレベルは、「1 (easy)」を選ぶ。中級と上級レベルはテストしていない。
この初級レベルでもエラーがでることがある。発見したら、コードを修正してほしい。
...省略...
...省略...
# 15-PUZZLE GAME
# ********************************
global d,ds$,sh,level,x,y,z
dim d(17)
dim ds$(17) # Board pieces
dim sh(4)
call introAndLevel
call buildBoard
call printPuzzle
do
print "To move a piece, enter its number: "
input x
while isMoveValid(x) = 0
print "Wrong move."
call printPuzzle
print "To move a piece, enter its number: "
input x
end while
d[z] = x
d[y] = 0
call printPuzzle
until isPuzzleComplete()
print "YOU WON!"
end
subroutine printPuzzle()
for p = 1 to 16
if d[p] = 0 then
ds$[p] = " "
else
s$ = string(d[p])
ds$[p] = left(" ", 3 - length(s$)) + s$ + " "
end if
next p
print "+-----+-----+-----+-----+"
print "|"; ds$[1]; "|"; ds$[2]; "|"; ds$[3]; "|"; ds$[4]; "|"
print "+-----+-----+-----+-----+"
print "|"; ds$[5]; "|"; ds$[6]; "|"; ds$[7]; "|"; ds$[8]; "|"
print "+-----+-----+-----+-----+"
print "|"; ds$[9]; "|"; ds$[10]; "|";ds$[11]; "|"; ds$[12]; "|"
print "+-----+-----+-----+-----+"
print "|"; ds$[13]; "|"; ds$[14]; "|"; ds$[15]; "|"; ds$[16]; "|"
print "+-----+-----+-----+-----+"
end subroutine
subroutine introAndLevel()
cls
sh[1] = 10
sh[2] = 50
sh[3] = 100
print "15 PUZZLE GAME"
print
print
do
print "Please enter level of difficulty,"
print "1 (easy), 2 (medium) or 3 (hard): ";
input level
until (1<=level) or (level<=3)
end subroutine
subroutine buildBoard()
# Set pieces in correct order first
for p = 1 to 15
d[p] = p
next p
d[16] = 0 # 0 = empty piece/slot
z = 16 # z = empty position
print
print "Shuffling pieces";
for n = 1 to sh[level]
print ".";
do
x = int(rand() * 4) + 1
begin case
case x=1
r = z - 4
case x=2
r = z + 4
case x=3
if (z - 1) % 4 <> 0 then
r = z - 1
end if
case x=4
if z % 4 <> 0 then
r = z + 1
end if
end case
until (r>=1) and (r<=16)
d[z] = d[r]
z = r
d[z] = 0
next n
cls
end subroutine
function isMoveValid(ax)
mv = 0
if (ax >= 1) or (ax <= 15) then
# Find position of piece ax
p = 1
while d[p] <> ax
p = p + 1
if p > 16 then
print "UH OH!"
end
end if
end while
ay = p:y = p
# Find position of empty piece
p = 1
while d[p] <> 0
p = p + 1
if p > 16 then
print "UH OH!"
end
end if
end while
az = p:z=p
# Check if empty piece is above, below ...
if (ay - 4 = az) or (ay + 4 = az) or ((ay - 1 = az) and (az % 4 <> 0)) or ((ay + 1 = az) and (ay % 4 <> 0)) then
mv = 1
end if
end if
isMoveValid = mv
end function
function isPuzzleComplete()
pc = 0
p = 1
while (p < 16) and (d[p] = p)
p = p + 1
end while
if p = 16 then
pc = 1
end if
isPuzzleComplete = pc
end function
練習問題 この15パズルコードをテストする
問題点を報告する。
Simple Space Game
このゲームは、なかなか良くできている。
このゲームの速度が早すぎるときには、 例えば goto mainloop
の前に速度を下げるために pause 0.01
文を挿入すればよい。百分の1秒遅くなる。
Wavplay
効果音
ハ長調の音階を演奏する
ハ長調、C major
C major の最初の音の周波数は、261.63Hz 。
参考リンク
Wikipedia - C major
したがって、ハ長調の音階を周波数になおし sound
によって BASIC 256 で演奏できる。
C,D,E,F,G,A,B,c は、次のようになる。
sound {261.63, 500, 293.66, 500, 329.63, 500, 349.23, 500, 392, 500, 440, 500, 493.88, 500, 523.25, 500}
このコードの意味は、第一音を 261.63Hz 持続時間 500ミリ秒 で出力、第二音を 293.66Hz ...
バッハを聴いて楽譜をコードにしてみる
自由落下 フリーフォール
地表では 9.807 メートル/秒2の加速度で地球の中心に向い落下する。重力のためである。したがって、この地表での重力加速度 g の値は、
重力加速度 g = 9.807 m/s2
である。
他の惑星では、重力加速度 g は異なるが、次の (1)落下距離 d
と (2)速度 v
を経過時間の関数として表す式は不変である。
これがニュートン(1642-1727)による万有引力の法則である。ニュートンは、リンゴが落るのを見てこれを発見したといわれるエピソードが有名であるが、真実かどうかはわからない。
1 2
d = - g t ... (1) 「d イコール 2分の 1 g t 2乗」
2
v = gt ... (2) 「v イコール g t」
ここで、
d,g,t,v の4つの変数の意味は、
d 落下距離
g 重力加速度
t 経過時間
v 速度
である。
ただ、重力とはいったい何なのかについては私達はよくわかっていない。しかし、この宇宙でどのように重力が働くかについてはわかっている。
質量 M
F = G M
1 M2 / r2
ここで G は、重力定数である。その値は、6.6726 × 10-11 m3 kg-1 s-2。
万有引力は、あらゆる物体に働いている。太陽と私達の間にも重力は作用している。太陽と地球の間の重力によって地球は太陽のまわりを回転している。月と地球の間の重力は、潮の満ち引きを引き起している。
太陽の質量: 1.989 × 1030 kg
地球の質量: 5.972 × 1024 kg
月の質量: 7.342 × 1022 kg
地球と太陽との平均距離: 149,597,870 km = 1.4959787 × 108 km
リンゴでもかまわないが、ここではボールを例にとりあげる。
ボールを落としてからの落下距離 d と落下速度 v は、変数 t (時間)の変化で表すことができる。
ある状態から、別の状態への変化は時間の変化で表すことができる。
ボールを高さ h から自由落下させた後の速度と高さは、それぞれ(2)と(1)式からわかる。
(1)式からボールを手から離すと、3秒後には 1/2 × 9.807 × 32 = 44.1315 メートル落下することがわかる。したがって、40 メートル余りの深い谷底へも 3秒後には届く。
(1)(2)式から、高さ20メートルでボールを自然落下させれば、空気抵抗などがないとすれば、ボールは地面に秒速 19.8 メートルの速度で衝突することがわかる。これは時速 71 キロメートル以上だ。高層階から物を落下させると危険だという理由は、9.807m/s2という重力加速度によるものである。
高さ20メートルからボールを落下させると、地面に秒速19.8メートルの速度で衝突することは、次の計算でわかる。
(1)式より
t2 = 2 * d / 9.807
x=2 * d /9.807 とおくと
t = √x
したがって、次のように計算できる。
2 * 20 / 9.807 = 40 / 9.807 = 4.07872
√4.07872 = 2.01946
9.807 * 2.01946 = 19.8048
現実には空気抵抗や風などがあるため、ボールの位置・速度の変化は、重力・空気抵抗・風などの合力をニュートン力学によって計算して決まる。
例えば、お腹を地面に向けてフリーフォールするスカイダイバーの地表面への最終速度は 195km/h (秒速 54 メートル)と言われている。重力と空気抵抗のバランスがとれ、この姿勢ではこれ以上加速しないようだ。
自由落下する物体についての式 (まとめ)
地上で落下する物体についての、式 (equation) をまとめて書いておく。
落下しはじめて t 秒後の距離:
1 2
d= - g t
2
d メートル落下するのかかる時間:
t= √(2d/g)
t 秒後の落下物体の瞬間速度 vi:
vi= gt
d メートル落下後の物体の瞬間速度 vi:
vi= √(2gd)
t 秒間 落下した物体の平均速度 va:
1
va= - g t
2
d メートル落下した物体の平均速度 va:
√(2gd)
va= -----
2
例として、最初の式から t 秒後と 落下距離 d メートルを計算すると次のようになる。
t d
1 秒後 1/2 × 9.807 × 1 × 1 = 4.9 メートル
2 〃 1/2 × 9.807 × 2 × 2 = 19.614 〃
3 〃 1/2 × 9.807 × 3 × 3 = 44.1315 〃
4 〃 1/2 × 9.807 × 4 × 4 = 78.456 〃
もう少しこまかく、0.5秒単位で落下距離を計算すると次のようになる[1]。
t d
0.5 1.225875
1.0 4.9035
1.5 11.032875
2.0 19.614
2.5 30.646875
3.0 44.1315
3.5 60.067875
4.0 78.456
4.5 99.295875
5.0 122.5875
参考リンク
四則計算の書き方 BASIC
BASIC-256を起動し、下のコードを「プログラム エディタ(Program Editor)」窓に入力し、「Run」をクリックすると、「テキスト 出力」の窓に結果が表示される。
+ たし算
- 引き算
* かけ算
/ わり算
\ 商の整数部分
^ べき乗
() 演算の順序を変える
変数 x の平方根を求めるには、関数 sqrt(x) を使う。
sqrt(x)
以下のコードを Program Editor に入力し実行する。
print 式
次の3行を BASIC256 の左上にある「プログラム エディタ」窓に入力する。
1行目の print は、20 × 2 ÷ 9.807 の計算結果をテキスト出力する。
2行目の sqrt(4.07872) は、4.07872 の平方根、すなわち2乗すると4.07872になる数を計算する関数を呼び出している。その結果は、printでテキスト出力される。
3行目は、重力加速度と秒数のかけ算、すなわち地面への衝突速度と、そのテキスト出力。
print 20*2/9.807
print sqrt(4.07872)
print 9.807*2.01946
sqrt(...) は、平方根を求める関数で、BASIC256に組込まれている。
変数
重力加速度、時間、速度について
変数、g, t, v を使う。
g=9.807
t=sqrt(20*2/g)
v=g*t
print t
print v
高度 20メートルからボールを落下させる。そのとき、
t 秒後の高さを t=0 から 2.1秒 まで 0.1秒ずつ繰り返し計算する
繰り返しを for ... next で書く。
変数 t を 0秒 から 2.1秒まで 0.1秒刻みで増やしながら、高さ y を計算する。
for t=0 to 2.1 step 0.1
...
next t
高さ y は次の式で計算できる。
y = 20 - 1/2 * g * t2
まとめてコードにする。
g=9.807
for t=0 to 2.1 step 0.1
y=20-1/2*g*t^2
next t
この for ... next を実行しても、計算は実行されるが、何も 出力 されない。
そこで、高さ y を計算したあとに、 print 命令で 時間と高度を出力する。
t 秒後と高度 y をプリントする。chr(9)は、秒と高度の間に間隔(タブ, tab)をあけてプリントするため。
次の文を y=h- ...
の次に挿入する。
print t;chr(9);y
入力文 input を使う
input h
g=9.807
t=sqrt(h*2/g)
v=g*t
print t
print v
入力文 input と出力文 print を対話型にする
高さを変数 h に入力 input する。
input "Height(m)? = ",h
g=9.807
t=sqrt(h*2/g)
v=g*t
print "Time: "; t; " sec"
print "Velocity: "; v; " m/sec"
秒と速度
g=9.807
for h=0 to 25
t=sqrt(h*2/g)
v=g*t
print t
print v
next h
print t;" ";v
時間と落下距離の表 ↩︎
問題 (2019.11.25 A)
時間 t と落下距離 d の表(a)を作るコードを、BASIC 256 で書いた。
空欄(ア)(イ)(ウ)を埋めよ。
g=9.807
print " t";chr(9);" d"
for t=0.5 to 5.5 step (ア)
y=1/2*g*t^2
print t;chr(9);y
next t
実行結果の表(a)
t d
0.5 1.225875
1.0 4.9035
1.5 11.032875
2.0 (イ)
2.5 30.646875
3.0 44.1315
3.5 60.067875
4.0 78.456
4.5 99.295875
5.0 122.5875
5.5 (ウ)
問題 (2019.11.25 A)
次の問いに答えるための式を書き、結果を求めよ。
- 20メートルの高さからボールを落すと、ボールは何秒後に地面にあたるだろうか?
- 25メートルから落すと、それは何秒後に、毎秒いくらの速度で地面に衝突するだろうか?
- 地上から20メートルの高さにボールを投げ上げるとする。ボールを離す手の位置を2メートルとすれば時速何キロで投げ上げればよいだろうか? 一般の成人男性は、この高さまでボールを投げ上げることができるだろうか?
- 徳島県にある祖谷谷のかずら橋は、長さ45メートル、幅2メートル、谷底まで14メートルの高さだといわれる。14メートルの高さから石を落すと何秒後に谷底にあたるだろうか?
- アメリカのグランドキャニオンは、長さ446キロメートル、幅29キロメートル、谷底までの深さ1857メートルといわれている。1857メートルの高さから石を落すと何秒後に谷底にあたるか?
問題 (2019.11.25 A)
宇宙工学を勉強中という彼女のツィッターに投稿されている動画のなかで、興味を持ったものを一つあげてください。
BASIC 256 の chr() 関数で日本語表示
次のプログラムを実行してみる。
最後の行に、「松山」と表示される。
関数 chr(26496) を使い、ユニコードから 文字「松」を表示させている。fromhex()は、16進数の 文字列"677e" を10進数に変換する関数を利用している。
松 677e 26494
山 5c71 23665
print chr(20001)
print fromhex("677e")
print chr(26494)
print fromhex("6bd7")
print chr(27607)
print fromhex("5c71")
print chr(26494) + chr(23665)
問題 (2019.12.02)
-
自分の名前を BASIC で表示してみる。
-
次の4文字を表示する。
ボールの自然落下をあらわすBASICコード
ボールの状態(位置、速度)を数値で表示する
単位は、メートル、秒。
ボールの状態
ボールを高さ y=h で手から離したときの
1 2
位置 y(t) = h - - gt
2
速度 v(t) = gt
コード
定数
- 重力加速度 g=9.807
初期値
- 位置 x=0, y=h
計算
t秒後の高さと落下速度を、t=0 から 2.1秒 まで 10分の1秒単位で計算してみる。
for t=0 to 2.1 step 0.1
g=9.807
h=20
y=h-1/2*g*t^2
next t
出力
経過した秒と高度をプリントする。chr(9)は、秒と高度の間に間隔(タブ)をあけてプリントするため。
次の文を y=h- ...
の次に挿入する。
print t;chr(9);y
練習問題 時間と落下速度
出力に落下速度をつけくわえたコードを書いてみる。
練習問題 自由落下を時間軸と速度軸のグラフにする
練習問題 落下するボールをグラフィック画面で表示する
練習問題 自然落下するボールをアニメーションにする
練習問題 落下したボールが地面で跳ねる様子
次のコードは、ボールの運動にニュートンの法則を取り入れている。
(a) 重力加速度をあらわす変数名は?
(b) 落下速度を計算しているのは何行目か?
print "Using Newton's laws to make the ball bounce realistically"
rem set up initial ball position and speed
x = 20
y = 100
r = 10
yvel = -1.0
xvel = 1.10
yacc = .0098
fastgraphics
loop1:
clg
rem change the downward velocity according to the acceleration
yvel = yvel + yacc
rem calculate new position
y = y + yvel
x = x + xvel
rem check for collisions
if y > 289 then yvel = -0.9 * yvel : y = 289 : xvel = xvel * 0.9
if x > 285 then xvel = -xvel : x = 285
if x < 10 then xvel = -xvel : x = 10
rem draw the ball
color darkblue
rect 0,0,300,300
gosub drawBall
if xvel * xvel < 0.0001 then end
goto loop1
drawBall:
color darkgray
circle x, y, r
color gray
circle x, y, r - 2
refresh
return
1089
3けたの数を思いうかべる。100の桁が1の桁よりも2以上大きい数にする。
たとえば、256 にしよう。この256の100の桁と1の桁を反転させ652をつくる。
次に、652から256を引く。652-256=396がえられる。
この396を反転した693を396に加える。すると、396+693=1089になる。
実は、このやり方で3けたの数を処理すると、結果はすべて1089になるのだ。
この「やり方」をコードで書くと次のようになる。
任意の3けたの数を入力して、確かめてみよう。
input "Input a number: ", n
a = reverse(n) - n
print reverse(n);" - ";n;" = ";a
print a;" + ";reverse(a);" = ";
print a+reverse(a)
end
# n -> x[2]x[1]x[0]
function reverse(n)
dim x(3) fill 0
x[0]=n % 10
x[1]=n \ 10
x[1]=x[1] %10
x[2]=n \ 100
return 100*x[0] + 10*x[1] + x[2]
end function
グラフィックス
BASIC 256 の右下のグラフィック窓の使い方
円を描く
グラフィック窓のなかに10個、それぞれ大きさ、色、位置をランダムに表示する
BASIC256 を起動する。
左の「プログラム エディター」窓に次のコードをコピーして、貼り付ける。
# 10 random circles
clg
for x = 1 to 10
call draw()
next x
end
function rnd(n)
rnd = int(rand*n)
end function
subroutine draw()
color rgb(rnd(256),rnd(256),rnd(256))
circle rnd(graphwidth), rnd(graphheight), rnd(graphwidth/10)
end subroutine
コードを動かすために、BASIC256のメニューの「Run」をクリックする。
コードの説明
clg
グラフィック窓のなかをクリアする。
for x=1 to 10
変数 x が持っている(に割りあてられた)値を 1,2,3,...,10 のように1からはじめて、10になるまで1ずつ増やす。この操作を next x まで反復する。
call draw()
サブルーティン draw() を呼び出す。
next x
x が持つ値 を 1 増やし、for x=1 to 10 の行に戻る。
end
メインプログラムを終了する。
function rnd(n)
rnd という名前をつけ、引数が n の 関数 を、次の行から end function までの行で定義する。
rnd = int(rand*n)
関数 rnd の値を、引数 n の値からイコールの右辺式を計算して定める。
右辺の意味は、rand は、0と0.9999...の間の乱数なので、それを n 倍し、小数部分を切り捨てる。
たとえば、rand が 0.3652で、n が 256だとすれば、
0.3652 * 256
93.4912
int(93.4912)
93
と計算し、
rnd(256) の値は、93 となる。
end function
関数の定義を終る。
subroutine draw()
プログラムは、全体を機能別に分割してつくられる。一つのメインプログラムと複数のサブプログラムからなる。
サブルーティン(subroutine)は、サブプログラムのことを指す。
書き方は、
subroutine 名前()
...
end subroutine
color rgb( ... , ... , ...)
色を、RGBに分解しそれぞれ 0から255 の数値 (256段階=8ビット)で示す。
例
red rgb(255,0,0)
green rgb(0,255,0)
blue rgb(0,0,255)
white rgb(255,255,255)
black rgb(0,0,0)
参考資料 BASIC 256 rgb function color name
circle ... , ...
図形をグラフィック画面のなかに位置、大きさを指定して表示する
stamp 命令を使ったコードを実行する。
color blue
rect 0,0,300,300
color green
sankaku = {{0, 0}, {100, 100}, {0, 100}}
stamp 100, 100, tri[]
stamp 200, 100, .5, tri[]
次のようなグラフィックが出力される。
宇宙船のゆくえ
万有引力の法則にしたがう例として、宇宙空間を航行する宇宙船を考えてみよう。ただし、宇宙船の航行を、現実の宇宙空間を非常に単純化したモデルの中で考えてみる。それは、宇宙船に引力をおよぼす天体は、地球と月だけとし、地球と月を宇宙空間に固定して考える。
定数
地球の質量
月の質量
宇宙船の質量
万有引力定数
地球の位置
月の位置
地球と月の距離
変数
宇宙船の位置
地球と宇宙船の距離
月と宇宙船の距離
宇宙船の速度
宇宙船の加速度
宇宙船に働く力
時刻
宇宙船の変数(速度、加速度、距離、引力)間の式
この宇宙船の軌道計算の前提では、宇宙船は自力の推進装置を持たない。宇宙船は、地球と月の引力のみで航行すると仮定する。
コード
定数
Constant:
C=3.844e8
mE=5.977e24
mM=7.352e22
G=6.673e-11
初期値
Hazime:
t=0.0: dt=60.0: n=60
x=-6500000.0: y=0.0: m=1000.0
vx=0.0: vy=10970.0
計算
Keisan:
for i=1 to n
t=t+dt
r=sqrt(x*x+y*y)
s=sqrt((x-C)*(x-C)+y*y)
fx=-G*mE*m*x/r/r/r -G*mM*m*(x-C)/s/s/s
fy=-G*mE*m*y/r/r/r -G*mM*m*y/s/s/s
ax=fx/m
ay=fy/m
vx=vx+ax*dt
vy=vy+ay*dt
x=x+vx*dt
y=y+vy*dt
next i
出力
Insatsu:
print t/3600;" ";x;" ";y;" ";vx;" ";vy;" ";r;" ";s
color red
plot 100+x/1e6, 100+y/1e6
goto keisan
Space ship ver. 0.01
# Space ship
# m.s 2019.9.15 ver. 0.1
Constant:
C=3.844e8
mE=5.977e24
mM=7.352e22
G=6.673e-11
cls
clg
print C;" ";mE;mM;G
graphsize 1000,1000
Hazime:
t=0.0: dt=60.0: n=60
x=-6500000.0: y=0.0: m=1000.0
vx=0.0: vy=10970.0
print "T (H) X (M) Y(M) VX(M/SEC) VY(M/SEC) R(M) S(M)"
Keisan:
for i=1 to n
t=t+dt
r=sqrt(x*x+y*y)
s=sqrt((x-C)*(x-C)+y*y)
fx=-G*mE*m*x/r/r/r -G*mM*m*(x-C)/s/s/s
fy=-G*mE*m*y/r/r/r -G*mM*m*y/s/s/s
ax=fx/m
ay=fy/m
vx=vx+ax*dt
vy=vy+ay*dt
x=x+vx*dt
y=y+vy*dt
next i
Insatsu:
print t/3600;" ";x;" ";y;" ";vx;" ";vy;" ";r;" ";s
color red
plot 100+x/1e6, 100+y/1e6
goto Keisan
end
Space ship ver. 0.02
# Space ship
# m.s 2019.9.15 ver 0.2
Constant:
C=3.844e8
mE=5.972e24
mM=7.342e22
G=6.674e-11
cls
clg
print C;" ";mE;mM;G
graphsize 1000,1000
Hazime:
t=0.0: dt=60.0: n=60
x=-6500000.0: y=0.0: m=1000.0
vx=0.0: vy=10970.0
print "T (H) X (M) Y(M) VX(M/SEC) VY(M/SEC) R(M) S(M)"
Keisan:
for i=1 to n
t=t+dt
r=sqrt(x*x+y*y)
s=sqrt((x-C)*(x-C)+y*y)
fx=-G*mE*m*x/r/r/r -G*mM*m*(x-C)/s/s/s
fy=-G*mE*m*y/r/r/r -G*mM*m*y/s/s/s
ax=fx/m
ay=fy/m
vx=vx+ax*dt
vy=vy+ay*dt
x=x+vx*dt
y=y+vy*dt
next i
Insatsu:
print t/3600;" ";x;" ";y;" ";vx;" ";vy;" ";r;" ";s
color red
plot 100+x/1e6, 100+y/1e6
goto Keisan
end
Web サーバーとの会話記録
インターネットのクライアント・サーバー方式について考えてみよう。
次のコードを BASIC256 で実行する。
これは、Webサーバーと会話をするためのプログラムコードの例である。
このコードは、4行目の site$ = " ... "
命令で、変数 site$
に WebサーバーのURL をあたえ、サーバ(site$)と会話をするプログラムである。
WebサーバーのURL(site$にあたえる文字列)を自分で書き換え、実行することができる。
以下は、BASIC256のサンプルプログラムの一部である。
# netgethomepage.kbs - connect to a web site and download
# the home page into a variable
site$ = "www.catherine.ac.jp"
port = 80
NETCONNECT site$, port
print "connected to " + site$ + ":" + port
get$ = "GET http://" + site$ + "/ HTTP/1.0" + chr(13) + chr(10)
get$ = get$ + chr(13) + chr(10)
NETWRITE get$
print "request written"
s$ = ""
do
chunk$ = netread
print "chunk '" + left(chunk$,10) + "..." + right(chunk$,10) + "'" + length(chunk$)
s$ = s$ + chunk$
# wait for more data / may need to adjust for a slower connection
pause .2
until not netdata
NETCLOSE
print "response"
print s$
print length(s$)
結果は、次のようになった。
1行目は、このプログラムを実行したコンピュータが www.catherine.ac.jp に80番ポートで接続したことを表示。
2行目は、サーバーに「ある要求」を送信したことを表示。
3行目は、サーバーから文字列が送信されてきたこと。その文字列の先頭10文字を切り取りチャンクし、
4行目に、その長さが447文字だということを表示。
5行目に、response と表示し、サーバーから送信されてきたものを6行目以下に表示している。
6行目は、ちょっとおいておき、
7行目を見ると、このサーバーは、 nginx を使っていることがわかった。いや nginx だからどうだということではないが、Apache を使っているところが多いので目立った。
8行目は、アクセスした時刻。GMT のときは、9時間足すと日本時間になる。
11行目で、サーバーとの接続を閉じたことを表示。
connected to www.catherine.ac.jp:80
request written
chunk 'HTTP/1.1 3...y></html>
'447
response
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Wed, 11 Dec 2019 00:49:00 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 236
Connection: close
練習問題
県内の学校、自治体のWebサーバーやマスメディアのサーバーとこのコードを使って会話してみよう。
www.city.matsuyama.ehime.jp
www.matsuyama-u.ac.jp
www.shinonome.ac.jp
www.pref.ehime.jp
www.rnb.co.jp
...
インターネットでチャット(会話)
BASIC 256 でインターネットの通信をつかって会話するコードを書いてみる。
クライアント・サーバー モデルを使う。
例:
クライアント サーバー
192.168.1.10 192.168.1.1
<------ ポート番号 ------>
9997
使い方 - 自分のコンピュータでサーバーとクライアントを起動する
(1) 自分のコンピューターの IP アドレスを調べる。
コマンドプロンプトを起動し、「ipconfig」とタイプすると IP アドレスが表示される。
(2) サーバー・プログラムを起動するため、下記のサーバーコードを BASIC-256 で Run
(3) クライアント・プログラムを起動するため、もうひとつ BASIC-256 を起動する。
この新しい BASIC-256 で、下記のクライアントコードを Run
(4) クライアント・プログラムで、「メッセージ」を作成して Enter
クライアントとサーバー間で会話がはじまる。
中断するには、サーバーで Stop
再開するには、サーバーで Run
サーバー
# get a message and send back success
print "wait for connection on " + netaddress()
netlisten 9997
print "got connection"
do
while not netdata
pause .1
print ".";
end while
n$ = netread
print n$
netwrite "I got '" + n$ + "'."
until n$ = "end"
netclose
クライアント
# have the user enter a message and send it to the server
input "enter message?", m$
netconnect "127.0.0.1", 9997
for t = 1 to 10
pause rand
netwrite t + " " + m$
print netread
next t
netwrite "end"
print netread
netclose
Country code and Flags
国の名前と国旗
国名、カントリーコード、国旗などの関係を知る。
グーグルのスプレッドシートにある国名と国旗のサイトを利用する。
グーグル Chrome ブラウザ で、docs.google.com spreadsheets にアクセスし、スプレッドシートを表示する。
次のような、形式のスプレッドシートが表示される。
A B C
1 Country URL Formula
2 Afganistan https://www.countr.. =IMAGE(B2,1)
3 Albania https://www.countr.. =IMAGE(B3,1)
実際に表示された例:
A, B, C 列の意味は?
A 列は、国名 Country name だとすぐわかる。英語表記。
B 列は、URL となっている。実際 B2 セルの内容は、
="https://www.countries-ofthe-world.com/flags-normal/flag-of-"&A2&".png"
となっている。
ちょっと見ると URL のようだが、二重の引用符で URL が囲まれている。しかも、先頭に=
が付いている。
C 列を見るともっとおかしなことに気付く。
C2セルにはアフガニスタン国旗のアイコンが表示されているが、セルの式は、=IMAGE(B2,1)
となっているのだ。
IMAGE(B2,1) 関数とは何だろう?
URL先の画像をセルのサイズに合せて表示しているようだ。
ちなみに、このグーグルの国旗へのURLを利用すれば、アルバニアの国旗などを表示することができる。
練習問題
docs.google.com spreadsheets をダウンロードし、エクセルで表示するとどうなるだろうか。
- デスクトップにフォルダーを作成して、そこに各国の国旗にくわえて次のプログラムを入れた。
dim f$(100)
n = 1
clg
f$[n]=dir("c:\Users\ore\Desktop\Flags")
while f$[n] <> ""
print n;" ";f$[n]
imgload 100,100,f$[n]
n=n+1
f$[n] = dir()
pause 3
end while
このプログラムの4行目は、ユーザ ore のデスクトップにあるフォルダー Flags にあるファイル名を次々に表示し、imgload 関数で国旗を表示する。表示間隔は、pause 3 で3秒あけている。
実際にフォルダーをつくり、そこへこのコードと国旗のファイルを入れて実行させてみよう。
最後にエラーが出るが、そのエラーが出ないようにするには、どのように修正すればよいだろうか。考えてみよう。
Day Number
クリスマスが日曜日になる年
2020年から2050年までを計算するコード。
M=12
D=25
for Y=2020 to 2050
gosub dayNumber
if W=0 then print Y
next Y
end
dayNumber:
A=Int((14-M)/12)
MM=M+12*A-2
YY=Y-A
W=D+Int((13*MM-1)/5)+YY+Int(YY/4)-Int(YY/100)+Int(YY/400)
W=W-7*Int(W/7)
return
その結果。
2022
2033
2039
2044
2050
月・日・年から曜日をもとめる
input "M= ",M
input "D= ",D
input "Y= ",Y
A=Int((14-M)/12)
MM=M+12*A-2
YY=Y-A
W=D+Int((13*MM-1)/5)+YY+Int(YY/4)-Int(YY/100)+Int(YY/400)
W=W-7*Int(W/7)
print W
end
このコードは、M,D,Y から W を計算する。W の値は、日曜日の 0 からはじまり土曜日の 7 の整数。 0,1,2,3,4,5,6 がそれぞれ 日月火水木金土 を意味している。
ただし、このコードはうるう年でなくとも2月29日の曜日を計算してしまう。
2020年1月の素数の日
Function isPrime(n)
If n < 2 Then Return False
If n = 2 Then Return True
If n % 2 = 0 Then Return False
limit = Int(Sqr(n))
For i = 3 To limit Step 2
If n % i = 0 Then Return False
Next i
Return True
End Function
For i = 20200101 To 20200131
If isPrime(i) Then
Print String(i); " ";
End If
Next i
1月から12月までの素数の日
20200109 20200111 20200121 20200123
20200223
20200309
20200429
20200511 20200529
20200613 20200619
20200703 20200711 20200721 20200723 20200729
20200801 20200813
20200903
20201021 20201029
20201101 20201113
20201227 20201231