2013年4月23日火曜日

X-BASIC/68とほぼ同機能となる関数

ここでは、X-BASIC/68とX-BASIC for iOSでほぼ同機能となる関数またはステートメントについて記述します。

機能 画像読み込み
X68版書式 int img_load(st;str[,x;int][,y;int][,b;int])
iOS版書式 int imgLoad(sx;float,sy;float,wx;float,wy;float,fname;str)
int picLoader(sx;float,sy;float,fname;str)
int pic_load(sx;float,sy;float,fname;str)
int cutLoader(sx;float,sy;float,fname;str)
int cut_load(sx;float,sy;float,fname;str)
相違点 imgLoad()はX68のべた画像フォーマット(GM?/GL?/GS?)をサポートしません。
技術的には可能なのですが、無用でしょうから。

機能 画像書き出し
X68版書式 int img_save(st;str[,x;int][,y;int])
iOS版書式 int jpegSave(fname;str,quality;int)
int pngSave(fname;str)
相違点 iOS版はX68のべた画像フォーマットでの書き出し(GM?/GL?/GS?)をサポートしません。
技術的には可能なのですが、無用でしょうから。

機能 テキスト画面色設定
X68版書式 color 属性
iOS版書式 tcolor(r;int[,g;int,b;int[,alpha;int]])
tatrb(atrb;int)
font(fontName;str[,pointSize;float])
相違点 iOS版では関数になり、 色指定はtcolor()、リバースはtatrb()、強調(ボールド)はfont()でフォントそのものの違いとして指定し分けます。

機能 画面全体のコントラストを指定する
X68版書式 contrast(ch;char)
iOS版書式 tBackgroundAlpha(alpha;float)
gBackgroundAlpha(alpha;float)が近い
相違点 厳密に言えば両者は異なりますが、実質的に同じ働きをします。
ただし、テキスト画面及びグラフィック画面はページ毎に独立制御になります。

機能 ファンクションキーの設定
X68版書式 key ファンクションキー番号,"文字列"
iOS版書式 setFunctionKey(no;int,title;str,keyCode;int)が近い
相違点 ファンクションキー番号の範囲が異なります。
また、 keyステートメントは設定した文字列がそのままinput等で入力されるのに対し、 setFunctionKey()は設定したキーコードを返します。
(iOSには基本的にキーコードという概念がないから。)

機能 マウスカーソル座標を得る
X68版書式 mspos(x;int,y;int)およびmsstat(x;int,y;int,bl;int,br;int)
iOS版書式 int getTouchPoint(xys;float1次元配列)が近い
相違点 iOSではマルチタッチが可能なため、座標は配列で返されます。

機能 ドット色を得る
X68版書式 int point(x;int,y;int)
iOS版書式 int bitmapPoint(x;int,y;int[,r;int,g;int,b;int,alpha;int])が近い
相違点 iOSではグラフィック画面のドット色を直接得る関数はありません。
ただし、bitmapOpen(fdirect=YES)時にはbitmapPoint()が同等の機能を果たします。

機能 単色領域内を塗りつぶす
X68版書式 int paint(x;int,y;int,col;int)
iOS版書式 int bitmapPaint(x;int,y;int[,r;int,g;int,b;int,alpha;int])が近い
相違点 iOSではグラフィック画面で単色領域を直接塗りつぶす関数はありません。
ただし、bitmapOpen(fdirect=YES)時にはbitmapPaint()が同等の機能を果たします。

機能 ドットデータを配列に読み込む
X68版書式 get(sx;int,sy;int,ex;int,ey;int,na;数値型一次元配列)
iOS版書式 bitmapGet(sx;int,sy;int,ex;int,ey;int,buff;int型一次元配列)が近い
相違点 iOSではグラフィック画面からドットデータを直接取得する関数はありません。
ただし、bitmapOpen(fdirect=YES)時にはbitmapGet()が同等の機能を果たします。
格納データには互換性はありません。。

機能 配列内のドットデータをグラフィック画面に描画する
X68版書式 put(sx;int,sy;int,ex;int,ey;int,na;数値型一次元配列)
iOS版書式 bitmapPut(sx;int,sy;int,ex;int,ey;int,buff;int型一次元配列)が近い
相違点 iOSでは配列内のドットデータを直接グラフィック画面に直接描画する関数はありません。
ただし、bitmapOpen(fdirect=YES)時にはbitmapPut()が同等の機能を果たします。

機能 ファイル名一覧を得る
X68版 files "パス名"
iOS版 int files(pathes;1次元文字列配列[,basedir;str][,ext;str][,fhave;int][,mode;int][,freg;int])
相違点 X68では指定パス内のファイルの一覧を表示する「コマンド」でしたが、iOS版ではファイル一覧を配列に格納する「関数」になっています。
iOS版はサブディレクトリ内まで取得するのも異なる所です。

機能 スプライトの状態を得る
X68版 int sp_set(pl;int,[x;int][,y;int][cd;int][,prw;int])
iOS版 int sp_setting(pl;int[,x;int][,y;int][,sp;int][,pb:int][,flip;int][,prw;int])
相違点 機能的には同じですが、引数の範囲と与え方に違いがあります。

X-BASIC/68の同名関数またはステートメントとの違い

ここでは、X-BASIC/68とX-BASIC for iOSで同名の関数またはステートメントにおける違いを記述します。
数値引数の型およびリターン値のみ異なる関数もありますが、それについては記述していません(数値引数の型は自動変換されます)。
ここでは、引数の詳細についての説明は省略します。

関数名 apage
X68版書式 int apage(page;char)
iOS版書式 int apage(page;int)
相違点 page番号の設定値
pageの値が全く異なります。必ず定数を使って設定してください。

関数名 a_play
X68版書式 void a_play(na;数値型一次元配列,sf;char,md;char[,lng;char])
iOS版書式 int a_setPlayData(fname;str[,rateNo;int])
int a_play(no;int)
相違点 X68版ではバッファへのデータ登録やサンプリングレートの設定も行いますが、iOS版ではデータ登録はa_setPlayData()で行い、a_play()は再生のみを制御します。

関数名 box
X68版書式 box(sx;int ,sy;int ,ex;int ,ey;int,col;int[,style;int])
iOS版書式 box(sx;float,sy;float,ex;float,ey;float [,style;int])
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
ビットマップにもbitmapBox()があります。

関数名 circle
X68版書式 circle(cx;int ,cy;int ,r;int ,col;int[,startAngle;int] [,endAngle;int] [,hv;int])
iOS版書式 circle(cx;float,cy;float,r;float [,startAngle;float][,endAngle;float][,clockwise;int][,ffill;int][,style;int])
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
startAngle/endAngleの単位が異なります。X68は度、iOSはラジアンです。
角度単位を変換してstartAngle/endAngleを同様に設定しても、描画結果は異なります。X68での描画結果は以下の通りです。








iOSではclockwise,ffill指定が追加されています。
X68の扁平率指定hvがiOSにはありません。
ビットマップにもbitmapCircle()および扁平率を指定できるbitmapEllipse()/bitmapEllipse2()があります。

関数名 fill
X68版書式 fill(sx;int ,sy;int ,ex;int ,ey;int ,col;int)
iOS版書式 fill(sx;float,sy;float,ex;float,ey;float)
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
ビットマップにもbitmapFill()があります。

関数名 line
X68版書式 line(sx;int ,sy;int ,col;int ,style;int)
iOS版書式 line(sx;float,sy;float,ex;float,ey;float[,ffill;int][,style;int])
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
styleの設定に制約があります。
ビットマップにもbitmapLine()があります。

関数名 hsv
X68版書式 int hsv(h;char,s;char,v;char)
iOS版書式 int hsv(h;int,s;int,v;int[,alpha;int])
相違点 h/s/vの値範囲が異なります。 おおよそ次の式で変換出来ます。
h=h68*(360/192)
s=s68*(256/32)
v=v68*(256/32)

関数名 rgb
X68版書式 int rgb(r;char,g;char,b;char)
iOS版書式 int rgb(r;int,g;int,b;int[,alpha;int])
相違点 r/g/bの値範囲が異なります。
X68000の色コードをiOSの色コードに変換するにはx68Color2iOSColor()を使います。

関数名 symbol
X68版書式 symbol(sx;int ,sy;int ,string;str,h;char,mo;char,col;int,an;char)
iOS版書式 symbol(sx;float,sy;float,string;str,fontName;str,pointSize;float)
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
X68版の以下の設定がiOS版にはありません。
h横方向の倍率
V縦方向の倍率
mo文字フォントの種類
an回転角度0~3(90度単位)
moはfontNameとpointSizeで相当します。

関数名 pset
X68版書式 pset(x;int ,y;int ,col;int)
iOS版書式 pset(x;float,y;float)
相違点 座標の他、色コードの指定方法が違います(iOS版ではgcolor()で別途設定します)。
ビットマップにもbitmapPset()があります。

関数名 vpage
X68版書式 vpage(page;char)
iOS版書式 int vpage(page;int,onoff;int)
相違点 pageの値が異なります。また、onoffが追加されています。

ステートメント名 width
X68版書式 width wx
iOS版書式 int width(wx;int[,wy;int][,fzenhan;int])
相違点 iOSでは関数になっています。また、wx=文字数は自由です。

ステートメント名 locate
X68版書式 locate x,y,カーソルスイッチ
iOS版書式 locate(x,y)
相違点 iOSでは関数になっています。また、カーソルスイッチの設定はありません。

関数名 inkey$()
X68版書式 inkey$(0)
iOS版書式 inkey$()
相違点 リアルタイムキー入力
iOSでは引数なし関数になっています。

関数名 pos
X68版書式 pos
iOS版書式 pos()
相違点 iOSでは関数になっています。

関数名 csrlin
X68版書式 csrlin
iOS版書式 csrlin()
相違点 iOSでは関数になっています。

関数名 beep
X68版書式 beep
iOS版書式 beep()
相違点 iOSでは関数になっています。

システム変数名 date$
相違点 iOSでは代入出来ません。

システム変数名 day$
相違点 iOSでは代入出来ません。

システム変数名 time$
相違点 iOSでは代入出来ません。

ステートメント名 goto
相違点 iOSでは行番号は使えません。

関数名 sp_stat(pl;int,md;int)
相違点 引数md=2に対するリターン値が異なります。またこれに伴い、md=3/4/5が追加されています。

関数名 sp_on
X68版 int sp_on([pl1;int][,pl2;int])
iOS版 int sp_on([pl1;int][,pl2;int][prw;int])
相違点 iOS版はprwの指定が出来ます。

関数名 sp_def
X68版 int sp_def(sp;int,na;char1次元配列[,sz;int])
iOS版 int sp_def(sp;int,ptn;intまたはchar1次元配列)
相違点 動作は同じですが、iOS版はパレットを使わない実色指定が可能のため、引数に相違があります。

関数名 sp_pat
X68版 int sp_pat(sp;int,na;char1次元配列[,sz;int])
iOS版 int sp_pat(sp;int,ptn;intまたはchar1次元配列)
相違点 動作は同じですが、sp_def()で与えるパターンの要素内容の違いから、パターンを入れる配列の型が異なります。またリターン値が異なります。

関数名 sp_color
X68版 int sp_color(p;int,col;int[,pb;int])
iOS版 int sp_color(p;int,col;int[,pb;int])
相違点 機能的には同じですが、色の指定方法が異なります。

関数名 bg_fill
X68版書式 int bg_fill(pg;int,sp;int)
iOS版書式 int bg_fill(pg;int,sp;int[,pb;int][,flip;int])
相違点 X68ではspにpbとflipの情報もORで入れ込む必要がありますが、iOS版は分離して与える必要があります。

関数名 bg_put
X68版書式 int bg_put(pg;int,x;int,y;int,sp;int)
iOS版書式 int bg_put(pg;int,x;int,y;int,sp;int[,pb;int][,flip;int])
相違点 X68ではspにpbとflipの情報もORで入れ込む必要がありますが、iOS版は分離して与える必要があります。

関数名 bg_get
X68版書式 int bg_get(pg;int,x;int,y;int)
iOS版書式 int bg_get(pg;int,x;int,y;int[,pb;int][,flip;int])
相違点 X68ではリターン値にpbとflipの情報もORで入っていますが、iOS版は独立して返します。

X-BASIC for iOSのX-BASIC/68との互換性について

X-BASIC for iOSは基本的に「SHARP X68000のX-BASIC v2.0」(以下X-BASIC/68) および「ぺけ-BASIC v0.2」と互換性を持っています。
プログラムもSHIFT-JISのまま読み込むことが出来ます。

主な違いは以下の通りです。
for iOS X-BASIC/68 ぺけ-BASIC
行番号 ×(自動削除)
gosub × ×
goto行番号 ×
goto "ラベル" 常時○ × 設定で○
goto *ラベル × × 設定で○
戻り値のないreturnで()の省略 ×
エディタ 内蔵 内蔵 なし(呼び出し可)
コマンド なし(一部関数化)あり なし
ダイレクト実行 不可 不可
?(print省略形) ×
その他省略形 × ×
文字列長 設定で変更可 任意に設定可 255バイト固定
配列次元 10次元 255次元 10次元
配列要素上限 OS状態による FREE設定まで OS上限まで
宣言なしint変数標準ではエラー 警告
dimなし配列 標準ではエラー 警告
表示コントロールコードCTRL-G/CTRL-J以外ありあり 一部あり
多バイト文字の
バイト単位出力による表示
×
chars2Sjis()/chars2UTF8()で処理可能
可変長配列 常時○ なし 設定で○
配列引数 常時○ なし 設定で○
using指定 文字列定数のみ 変数も可文字列定数のみ
using ! 1文字 1バイト 1バイト
using "%" 不足桁を0で埋める%が表示される %が表示される
e表現float
(>3e10,4E-10など)
×(バグ)
単項演算子の連続
(-notなど)
×(バグ)
起動時引数 なし なし 設定で○
startup.bas
(自動実行ファイル)
あり なし なし
変数の初期化 常時 常時 設定でなし
エラー停止 コンパイル時は全体
実行時発生行
実行時発生行 コンパイル時発生行
実行時発生行
date$/time$ 代入不可 代入可 代入可
inkey$ あり
ただしタッチまたはファンクションキー設定が必須
あり あり
外部関数互換性 機種依存分以外 あり あり
マルチステートメント 可(省略不可)
//コメント × ×
空行 ×
ファイルエンド サイズ/&h1a &h1a必須 サイズ/&h1a
文字コード UTF-8/SHIFT-JISSHIFT-JIS SHIFT-JIS
変数宣言時代入 制約なし 定数式のみ 制約なし
.cnf設定 一部SETUP あり 拡張あり
マルチステートメントについてはわかりにくいので補足しておきます。
X-BASICでは ':' で区切ることでマルチステートメントを書けますが、X-BASIC/68ではその後の文を省略できません(存在しないとエラーになる)。iOS版及びぺけ-BASICでは省略できます。
この差は特にcase文で顕著になります。
case 1:    X-BASIC/68ではエラーになるのでcase 1と記述しなければならない


オーバーフローチェック
for iOSX-BASIC/68 ぺけ-BASIC補足
charで255+1 0 エラー 0 8ビットオーバーフロー
0-1 255 エラー 255 8ビットアンダーフロー
dim a(65536) dim a(0)相当 エラー dim a(0)相当配列要素数は16ビットで管理されているから

また、ハードやOSの違い等により、以下の項目の取り得る値や規則が異なります。
  • テキスト座標
  • グラフィック座標(float)
  • スプライト枚数(定義/表示)、座標
  • 色コード
  • ファイル名規則
  • メモリの格納順はL→H(リトルエンディアン)
一部はX-BASIC/68→X-BASIC for iOS変換関数が存在します。

さらに、ほぼ同じ動きを目指した関数でも、iOSとX68実機の動作の違いにより、結果が微妙に異なる場合があります。特にグラフィック系は、iOSは基本的にアンチエイリアスと合成描画を基本としているため、描画結果がX68と異なる場合が多々あります。さらに、テキスト画面の座標とグラフィック画面の位置関係がX68とは異なります。

ぺけ-BASICのバグについて(見つけ次第更新)

X-BASIC for iOSの開発に際しては、「ぺけ-BASIC」を大いに参考にさせていただきました。

中間コードにコンパイルしてから実行するという構造もそこからいただきました。

「ぺけ-BASIC」は物理的に速くないX68000上で、出来るだけ速くX-BASICを動かそうとする優秀なプログラムですが、いかんせんオールアセンブラな上にメンテナンス性が考慮されてない記述だったため、解析はきわめて難しいものでした。
(68000というMPUやアセンブラHASに強く依存する記述や、定数化してない即値記述が非常に多いなど。)

原作者の方が「バグ取り以外はしない」とおっしゃられていましたが、実際のところ「それ以外出来ない」状況にあったというのが真実でしょう。
少しでもいじろうもんなら他の部分に影響を与える、そんな、ある意味「絶妙なバランス」でした。

今回の開発ではX-BASIC/68だけでなくぺけ-BASIC上でも動作確認をしましたが、
いろいろとバグを発見しました。今更ではありますが、ここに公開しておきます。
もちろん、iOS版ではすべて解消しています。
  • floatの変数初期化サイズが足りていない
    要するに宣言しただけでは0.0にならないと言うことです。
    float変数を使う場合、明示的に初期化しないと正しくない結果をもたらします。

  • float定数のみ f1 * -f2で「無効な命令が発生する」
    「例」4.321*-5.01
    X-BASIC/68はOK
    int/charはOK

  • 単項演算子が連続すると式エラーが出る
    not -/-notなど
    float/int/charすべて
    X-BASIC/68はOK
    ()を付ければ回避できる

  • usingの結果および書式指定の方法がX-BASIC/68と異なる
    "+##"の結果
    "\.#"の結果(整数部なしで\をつける)
    ^^^^^指定時に,を付けたらエラーになる
    X-BASIC/68ぺけ
    -^^^^^^^^^^-
    +****+

  • printの数値表示時の桁位置が違う
    X-BASIC/68符号(+の時は空白)+数値+空白1文字
    ぺけ空白+符号付き数値+空白

  • e表現floatが使えない
    3.14e10など

  • then {またはelse {の後に:/*と書くとエラーになる
    コメントを書く場合、:なしで/*と書かなければならない
    内部的にはマルチステートメントの処理に問題がある
    X-BASIC/68でもelse {で発生する。

  • tan(pi(1.0/2.0))の計算結果がおかしい
    6.2184311638237E+015となってしまう。
    正解は1.6331239353195E+016
    X-BASIC/68も同じなので、XM6 typeG/xm6i、もしくはfloat2.xのバグかもしれない。ちなみに、sin()/cos()で計算すると正しい。
    sin(pi/2)/cos(pi/2)=1.6331239353195E+016
    以下も正しい。
    tan(pi/4)=1
    tan(pi/8)=0.4142...
  • 配列を引数に持つ関数の中で、子関数にその配列を渡すときエラーが発生する
    func testFunc(n;int,s(4,1);str)

    subFunc(s) :// ここでエラーが発生する
    endfunc
    func subFunc(s(4,1);str)

    endfunc
    引数配列の要素数は省略が可能=呼び出し時に確定されるため、コンパイル時には未定のままになっています。 ところが、その確定処理が抜けているためエラーが発生しています。
    なお、要素数を省略してない場合もエラーになります。

  • 関数の引数名が関数名と同じだったとき、func文で変数二重宣言エラーが発生する
    関数の引数名は関数名と同じにしないでください。
    なおこれはX-BASIC/68では発生しませんが、ぺけ-BASICで発生します。
    バグというより仕様です。両者の数少ない非互換部分の1つです。

  • func message(n;  int , rt;  int)のように、引数型を示す;の後にスペースを入れると内部エラーが発生する。
    スペースを取るとOK。X-BASIC/68では発生しない。

  • using "~"の後ろにスペースを置くとエラーが発生する
    using "###";a /* OK
    using "###" ;a /* エラー
    X-BASIC/68では発生しない。

  • 0除算をしてもエラーが発生しないことがある
    例えば、以下の時にそうなります。
    print "1/0=";1/0 /* エラーが発生するはずなのに1と表示される
    /*
    int a=0
    int b=0*(1-1#/(a*a))
    print "b=";b  /* 2147483647と表示される
    /* ちなみに
    print 0*(1-1#/(a*a)) /* #NANと表示される
    int b=0*(1-1/(a*a))  /* とするとエラーが発生する
    どういう条件ではエラーが発生しないのかまでは突き止めてませんが、どうも整数はエラーになっても実数演算で0になるときはエラーにならないような感じです。
    なお、X-BASIC/68ではすべてエラーになります。

以下は、ソース内に見つけた不具合らしき部分です。実動作では確認してません。
  • 以下の物が32767個を超えると異常動作を起こす
    変数の個数(グローバル/ローカル別)
    ラベル最大数
    行番号の実利用数
  • 行番号に65535を使うと異常動作する
  • func で配列引数を取った時、dim(n,m の後に)以外の文字があると其の分ワークが無駄に消費される
    たぶん暴走はしないけど、おかしい
  • 配列の初期化
    {}の個数が宣言した要素数より多い時、中間コードエリアを破壊する
    一応後でエラーを出す処理は入っているが、そこまで行くまでに(メモリ内容を破壊して)異常動作を起こす可能性がある
  • 関数で配列引数のとき3次元以上の配列を与えてもエラーが発生しない
    次元判定に使うレジスタを間違っている
  • 配列への代入がおかしい
    レジスタの参照を間違っているので。
    たぶん ぺけ-BASIC はたまたま動いてるだけ。
  • 文字列定数加算をしたとき
    その合計サイズが256バイトを超えるとワークを破壊する
    その領域を別の文字列変数がすでに使っている場合、その内容が化ける
    加算を繰り返すと其の都度新しいワークを割り付けるため、メモリ不足に陥りやすい
  • 拡張配列を関数の引数にしたとき、要素数テーブルを過剰にクリアしてしまう
  • 配列宣言で、閉じ括弧がなくソースが終わったときにハングアップする。
    多次元配列で,の後がなくソースが終わったときも同様。
なんにしても、動作を考える上でぺけ-BASICが参考になったのは紛れもない事実です。
この場で感謝いたします。

ーーーーーーーーーーーーーーーーーーーーーーーー
おまけ
X-BASIC/68のバグ。

・引数なし関数の定義をするとき、func f( ) とカッコ内にスペースが有るとき、呼び出し側で「式の記述が間違っています」エラーが発生する

f() :/* ここで発生

引数なしの時は ()としなければならない。
 ぺけーBASICでは発生しない。

・プログラムファイルの終端を&h1aだけで判断しているため、それがないファイルを読み込ませた時、プログラムにゴミが入ることがある。
変な行が途中に入ってエラーが発生する事が多い。
これはバグというより「仕様」。

2013年3月5日火曜日

爆弾探しゲーム

いわゆる「マインスイーパー」です。
bomb11.aiffも入れる必要があります。
/*****************************************************************
// 爆弾捜しゲーム
//    アイディアは違うけど、プログラムは
//    Copyright (C) 1993,2012 by AIG-SOFT
//        うわぁ、約20年ぶりに移植したのか!
/*****************************************************************
/* 定数 じゃなくて 変数

font("IPAGothic")
int fzenhan
int WX=64
int WY=width(WX,,fzenhan)
int xw=1:/* 全角1文字の桁数
if fzenhan then xw=2

/*****************************************************************

int MX =(WX/2)-2    :/* マップ最大横幅(-2は枠用)
int MY =19          :/* マップ最大縦幅
int MXX=5           :/* マップ最小横幅
int MYY=4           :/* マップ最小縦幅

int BOMB='*'        :/* 爆弾コード
int ERR=9           :/* 判定間違い
int BMBIT=bit(7)    :/* 爆弾在るはずビット
int CHBIT=bit(6)    :/* わかんないビット
int OPBIT=(BMBIT or CHBIT)    :/* オープン状態を示すビット
int NOPBIT=(not OPBIT)        :/* キャラクターのみを取り出すビット

/* 画面表示ホーム座標
int SX=2    :/* sx>=2 & sx+(MX+1)*2<画面x幅
int SY=4    :/* sy>=4 & sy+MY+1    <画面y幅

int ESC=&h1B
int CR =&h0d

/*****************************************************************
/* グローバル変数

dim char map( (64/2),19)    :/* (MX,MY)だけど変数だから使えない 現在マップ
dim char map0((64/2),19)    :/* (MX,MY) 表示用仮想画面

dim int    touchNo(10)      :// タッチエリア番号
int touchCnt    :// タッチエリア数

int wx,wy       :/* マップ幅
int seed,bomb   :/* 全爆弾数,爆弾ありそう数
int all         :/* 開けるべき全ますの数
int ts,dt       :/* 開始時間、経過時間

/*****************************************************************

int ret
int minbomb,maxbomb
/* フィールド幅、爆弾個数設定
str widthStr,heightStr,bombStr,defaultStr,messageStr
if isLocalizeJapan() then {
    widthStr ="横幅"
    heightStr="縦幅"
    minbomb=MXX*MYY/8 :/* 最小1/8
    maxbomb=wx*wy/2     :/* 最大1/2
    bombStr="爆弾数"
    defaultStr="標準"
    messageStr="メッセージ"
} else {
    widthStr ="width "
    heightStr="height"
    minbomb=MXX*MYY/8 :/* 最小1/8
    maxbomb=wx*wy/2     :/* 最大1/2
    bombStr="bombs"
    defaultStr="default"
    messageStr="message"
}
    print widthStr ;"(";MXX;"~";MX;")";
    dim str menues(3)={"10","20","30"}
    menues(3)=defaultStr
    wx=selectMenu(widthStr,menues):// selectMenu()の最終項目は特別
    if wx=3 then wx=2
    wx=(wx+1)*10
    print wx
//    input wx
    print heightStr;"(";MYY;"~";MY;")";
    menues={"5","10","15","19"}
    repeat
        wy=selectMenu2(heightStr,menues)
    until wy<>-1
    wy=5*(wy+1)
    print wy
//    input wy
    
    if wx<MXX then wx=MXX
    if wx>MX  then wx=MX
    if wy<MYY then wy=MYY
    if wy>MY  then wy=MY
    minbomb=MXX*MYY/8 :/* 最小1/8
    maxbomb=wx*wy/2     :/* 最大1/2
    print bombStr;"(";minbomb;"~";maxbomb")";
    menues={"50","100","150","200"}
    seed=selectMenuWithMessage(bombStr,messageStr,menues)
    seed=50*(seed+1)
    print seed
//    input seed
    if seed<minbomb then seed=minbomb
    if seed>maxbomb then seed=maxbomb

int sno=a_setPlayData("bomb11.aiff")
a_play(sno)

/* メインルーチン
repeat
    /* 乱数初期化
    srand2()
    
    /* 爆弾配置
    all=BombSeed(seed)
    bomb=0
    BombCount()
    dt=0:/* 経過時間
    
    /* 初期画面表示
    InitScreen()

    /* キー操作
    ret=CursorMove()
    
    /* 終わり判定
    if ret=-2 then break:/* 強制終了
    switch ret
        case -1:/* やり直し
            MapPrintAll(YES):/* 全表示
            break
        case 0: /* Game clear
            GameClear()
            break
        case 1: /* Game over
            MapPrintAll(YES):/* 全表示
            GameOver()
            break
    endswitch

    /* 再開処理
    locate(20,2)
    if isLocalizeJapan() then {
        print "《もう一度しますか?》";
        setFunctionKey(0,"はい"  ,CR)
        setFunctionKey(1,"いいえ",ESC)
    } else {
        print "<< Try Again ? >>";
        setFunctionKey(0,"YES",CR)
        setFunctionKey(1,"NO" ,ESC)
    }
    displayFunctionKey(YES,0,1)
    repeat
        ret=inkey()
    until ret<>0
    displayFunctionKey(NO,0,1)
    // タッチエリアの解除
    // 一旦解除してから再設定しないと重なり続ける
    resetTouchArea()
until (ret=ESC)
a_end(sno):// 音声バッファー解放
if isLocalizeJapan() then {
    print "終了"
} else {
    print "end"
}
end

/*****************************************************************
/* 関数群
/*****************************************************************

func int CursorMove()
/* カーソル移動&操作
int x,y,c
int t
    /* 初期座標
    /* 爆弾が無い座標に置く
    for x=0 to wx-1
        for y=0 to wy-1
            if ((map(x,y) and NOPBIT)<>BOMB) then goto "CM1"
        next
    next
label "CM1"
    ts=time():/* 開始時間
    while YES
        /* カーソル位置を反転表示
        c=map(x,y)
        tatrb(ATRB_REVERSE)
        locate2(x,y)
        print printChr$(c);
        tatrb(ATRB_NORMAL)
        
        // キー入力待ちしながら時計を回す
//        int cnt=0
        while (not kbhit())
            /* キー入力の無い間
            t=time()
            if t-ts>dt then { :/* 秒が変った
                dt=dt+1
                PrintTime(dt)
//                beep2(0)
//                print "cnt=";cnt
            }
//            inc(cnt)
        endwhile
        
        /* カーソル位置を普通表示
        locate2(x,y)
        print printChr$(c);
        //
        // キー操作判定
        c=inkey()
        beep2(0)    :// click sound
        switch c
            case &h1b: /* やり直し
                return(-1)
            
            /* カーソルは画面端でロールする
            case '2': /* ↓
                if y<wy-1 then y=y+1 else y=0
                break
            case '4': /* ←
                if x>0 then x=x-1 else x=wx-1
                break
            case '6': /* →
                if x<wx-1 then x=x+1 else x=0
                break
            case '8': /* ↑
                if y>0 then y=y-1 else y=wy-1
                break
            
            case '5': /* Check
                CheckMapPoint(x,y)
                MapPrint()
                /* チェックでは全開きにはならない
                break
            
            case ' ': /* Open
                if OpenMapPoint(x,y) then return(YES):/* game over
                /* 表示
                if MapPrint() then return(NO)
                break
        endswitch
    endwhile
    return (YES)
endfunc

/*****************************************************************

func int MapPrint()
/* マップを表示する&仮想画面変更
/* リターン値:0=まだ全ては開いていない , 1=全部開いた
int x,y,c
int all0=0
    for y=0 to wy-1
        for x=0 to wx-1
            c=map(x,y)
            if map0(x,y)<>c then {
                /* 画面に変更がある
                locate2(x,y)
                print printChr$(c)
                map0(x,y)=c:/* 仮想画面も変更
            }
            /* 開いているポイントを数える
            if ((c and OPBIT)=OPBIT) then all0=all0+1
        next
    next
    return(all0=all)
endfunc

/*****************************************************************

func MapPrintAll(mode;int)
/* マップ全表示
/* mode : 0=そのままで , 1=すべて開いて(間違い判定付き)
int x,y,c
str ls
    for y=0 to wy-1
        ls=""
        for x=0 to wx-1
            c=map(x,y)
            if mode then {
                if (c and OPBIT)=BMBIT then {
                    /* 爆弾ありとしているが・・
                    /* そこに爆弾がなければ間違い
                    if (c and NOPBIT)<>BOMB then c=ERR
                }
                c=(c or OPBIT):/* 開く
            }
            ls=ls+printChr$(c)
        next
        locate2(0,y)
        print ls
    next
    // color(7)
endfunc

/*****************************************************************

func str printChr$(c;int)
/* キャラクター表示
/* c : bit6,7 = 開き済み(11)/チェックマーク(10)/爆弾マーク(01)/閉じている(00)
/*     bit0-5 = マップ状態 &h00~&h3f
str cs
    int cc=(c and OPBIT)
    if cc=0 then {
        /* 閉じている
        return ("□")
    }
    if cc=CHBIT then {
        /* CHBIT チェックマーキング中
        return ("?")
    }
    if cc=BMBIT then {
        /* 爆弾ありマーキング中
        return ("☆")
    }
    if cc=OPBIT then {
        /* 開いている
        switch (c and NOPBIT)
            case  0:cs= "・":break
            case  1:cs= "1":break
            case  2:cs= "2":break
            case  3:cs= "3":break
            case  4:cs= "4":break
            case  5:cs= "5":break
            case  6:cs= "6":break
            case  7:cs= "7":break
            case  8:cs= "8":break
            case  9:/* 間違い
                cs= "×"
                break
            case '*':/* 爆弾
                cs= "★"
                break
        endswitch
    }
    return (cs)
endfunc

/*****************************************************************

func locate2(x;int,y;int)
    locate(SX+(x)*xw,SY+y)    :/* *xw for 全角文字
endfunc

/*****************************************************************

func WakuPrint(yoko;str,tate;str,kado;str,fall;int)
/* マップ枠表示
int i
    /* 横線
    str yokos=""
    for i=0 to wx-1:yokos=yokos+yoko:next
    locate2(0,-1):print yokos
    locate2(0,wy):print yokos

    /* 縦線
    if fall then {
        // 内側も消す=速い
        str tates=tate+space$(wx*xw)+tate
        for i=0 to wy-1
            locate2(-1,i):print tates;
        next
    } else {
        // 枠だけ=遅い
        for i=0 to wy-1
            locate2(-1,i):print tate;
            locate2(wx,i):print tate;
        next
    }
    
    /* 角
    locate2(-1,-1):print kado;
    locate2(-1,wy):print kado;
    locate2(wx,-1):print kado;
    locate2(wx,wy):print kado;
endfunc

/*****************************************************************

func InitScreen()
/* 初期画面表示
    cls()
    WakuPrint("-","|","+",YES)
    MapPrintAll(NO)
    locate(5,0)
    if isLocalizeJapan() then {
        print using "マップ幅:##×##  爆弾数:###/###  時間:#####";wx,wy,bomb,seed,dt
            /*         0         1           2         3          4    
            /*        +0123456789012345678901234567890123456789012    
            /*        +locate
    } else {
        print using "map size:##×##  bombs :###/###  time:#####";wx,wy,bomb,seed,dt
    }
    str open$,exit$
    if isLocalizeJapan() then {
        open$="開く"
        exit$="中断"
    } else {
        open$="open"
        exit$="exit"
    }
    int x=WX/2-18
    int y=SY+wy+2
                    //     012345678901234567890123456789
    locate(x,y+0):print "      ┏━┓"
    locate(x,y+1):print "      ┃↑┃"
    locate(x,y+2):print "      ┗━┛"
    locate(x,y+3):print "┏━┓┏━┓┏━┓    ┏━━┓"
    locate(x,y+4):print "┃←┃┃?┃┃→┃    ┃";open$;"┃"
    locate(x,y+5):print "┗━┛┗━┛┗━┛    ┗━━┛"
    locate(x,y+6):print "      ┏━┓"
    locate(x,y+7):print "      ┃↓┃"
    locate(x,y+8):print "      ┗━┛"
    
    int i=0
    touchNo(inc(i))=setTouchAreaWithText(x+ 6,y  ,xw*3,3,'8',YES,125,0,5,100)
    touchNo(inc(i))=setTouchAreaWithText(x+ 6,y+6,xw*3,3,'2',YES,125,0,5,100)
    touchNo(inc(i))=setTouchAreaWithText(x   ,y+3,xw*3,3,'4',YES,125,0,5,100)
    touchNo(inc(i))=setTouchAreaWithText(x+12,y+3,xw*3,3,'6',YES,125,0,5,100)
    //
    touchNo(inc(i))=setTouchAreaWithText(x+ 6,y+3,xw*3,3,'5',YES,150,50, 5,120):/* check
    touchNo(inc(i))=setTouchAreaWithText(x+22,y+3,xw*4,3,' ',YES,150, 5 ,5,120):/* open
    touchCnt=i
    //
    setFunctionKey(0,exit$,ESC)
    displayFunctionKey(YES,0,0)
endfunc

func resetTouchArea()
// タッチエリアの解除
int i
    for i=0 to touchCnt
        removeTouchArea(touchNo(i))
    next
    touchCnt=0
endfunc

/*****************************************************************

func PrintBombCount()
/* 残り爆弾数表示
    locate(5+26,0)
    print using "###";bomb
endfunc

/*****************************************************************

func PrintTime(dt;int)
/* 経過時間表示
    locate(5+42,0)
    print using "#####";dt
endfunc

/*****************************************************************

func GameClear()
/* ゲームクリア時画面表示
    /* 枠の模様を代える
    beep()
    WakuPrint("◇","◇","◇",NO)
    beep()
    locate(6,1)
    if isLocalizeJapan() then {
        print "§§ おめでとう! あなたは総ての爆弾を捜し当てました §§";
    } else {
        print "<< Congratulations! You've turned up the bomb of all >>";
    }
endfunc

/*****************************************************************

func GameOver()
/* ゲームオーバー時画面表示
    /* 枠の模様を代える
    a_play(sno)
    WakuPrint("☆","☆","☆",NO)
    a_play(sno)
    locate(10,1)
    if isLocalizeJapan() then {
        print "@@ あなたは爆弾にぶち当たってしまいました @@";
    } else {
        print "@@ You've hit a bomb @@";
    }
endfunc

/*****************************************************************

func CheckMapPoint(x;int,y;int)
/* マップ上のポイントをチェックする
int c
    c=map(x,y)
    c=(c and OPBIT)
    if c=OPBIT then {
        /* すでに開いている
        /* 開いている所を調べることは不用
        beep()
        return()
    }
    if c=0 then {
        /* 閉じている -> 爆弾ありそう
        map(x,y)=(BMBIT or map(x,y))
        bomb=bomb+1
        PrintBombCount()
        return()
    }
    if c=BMBIT then {
        /* 爆弾ありそう -> チェックしてね
        map(x,y)=(c and NOPBIT)or CHBIT
        return()
    }
    if c=CHBIT then {
        /* チェックしてね -> 閉じる
        map(x,y)=(NOPBIT and map(x,y))
        bomb=bomb-1
        PrintBombCount()
    }
endfunc

/*****************************************************************

func int OpenMapPoint(x;int,y;int)
/* マップ上のポイントを開く
int c
    c=map(x,y)
    if ((c and OPBIT)=OPBIT) then {
        /* すでに開いている
        /* 開いているところを再度開くことは不用
        beep()
        return(NO):/* 警告以外は何もしない
    }
    if ((c and NOPBIT)=BOMB) then {
        /* 爆弾を開けてしまった
        a_play(sno)
        return(YES):/* game over
    }
    /* そこはまだ開いていない所なので開ける
    if (c=0) then {
        /* 周りに爆弾がない所ならペイント型で開く
        PaintMap(x,y)
    } else {
        /* 周りに1つでも爆弾がある時は1ポイントだけ開ける
        map(x,y)=(OPBIT or map(x,y)):/* 開けた印
    }
    return(NO)
endfunc

/*****************************************************************

func PaintMap(x;int,y;int)
/* マップの(x,y)から0の点を開く
/* 基本的にはペイントと同じルーチンになるが、境界まで開くのが違う
int c,xs,xe
    if map(x,y)<>0 then {
        /* 最初の点が0でなければ終わり
        return()
    }
    /* 0 <- x : 左サーチ
    xe=x+1 :/* 右へ捜し始めるポイント
    while x>=0
        c=map(x,y)
        if ((c and OPBIT)=0) then {
            map(x,y)=(OPBIT or map(x,y))
        }
        if (c<>0) then break:/* 境界
        /* 境界も開かれる
        //    境界は爆弾ではない。/ border is not bomb
        //    なぜなら爆弾の周りには1~8が必ずあるから。
        x=x-1:/* 左へ
    endwhile
    if x<0 then xs=0 else xs=x
    /* xs=線分左端(境界も含む)

    /* x -> wx-1 : 右サーチ
    while xe<=wx-1
        c=map(xe,y)
        if (c and OPBIT)=0 then map(xe,y)=(OPBIT or map(xe,y))
        if c<>0 then break:/* 境界
        xe=xe+1 :/* 右へ
    endwhile
    if xe=wx then xe=xe-1
    /* xe=線分右端(境界を含む)
    if y>0    then PaintMapSub(xs,xe,y-1):/* 上チェック
    if y<wy-1 then PaintMapSub(xs,xe,y+1):/* 下チェック
endfunc

/*****************************************************************

func PaintMapSub(xs;int,xe;int,yy;int)
/* PaintMap()サブルーチン:上下チェック用
int x,c
    for x=xs to xe
        c=map(x,yy)
        if c=0 then {
            PaintMap(x,yy)
        } else {
            if (c and OPBIT)=0 then map(x,yy)=(OPBIT or map(x,yy)):/* 境界も開く
        }
    next
endfunc

/*****************************************************************

func int BombSeed(seeds;int)
/* マップ内に爆弾をまく
/* seeds : 爆弾個数 < wx*wyにすること
/* 乱数の初期化は外部で行なうこと
int x,y
int all
    /* マップクリア
    for y=0 to wy-1
        for x=0 to wx-1
            map(x,y)=0
        next
    next
    
    /* 要開き数:爆弾以外すべて
    all=wx*wy-seeds
    
    /* 爆弾配置
    while seeds>0
        x=rand2(wx)
        y=rand2(wy)
        if map(x,y)=0 then {
            /* 爆弾を置く
             map(x,y)=BOMB:/* マップ
            map0(x,y)=BOMB:/* 仮想画面
            seeds=seeds-1 :/* 残りを1つ減らす
        }:/* そこにすでに爆弾がある時は別の場所を探す
    endwhile
    
    return(all)
endfunc

/*****************************************************************

func BombCount()
/* マップ内の爆弾状況を書き込む
/* 各ポイント毎の周りの爆弾の数をあらかじめ書き込む
int x,y,xx,yy,xs,ys,xe,ye,c
    for y=0 to wy-1
        ys=y-1:if ys<0    then ys=0
        ye=y+1:if ye>wy-1 then ye=wy-1
        for x=0 to wx-1
            if map(x,y)=BOMB then continue:/* 爆弾の所はスキップ
            xs=x-1:if xs<0    then xs=0
            xe=x+1:if xe>wx-1 then xe=wx-1
            /* 周りをカウント
            c=0
            for yy=ys to ye
                for xx=xs to xe
                    if map(xx,yy)=BOMB then c=c+1
                next
            next
            /* c=0~8
             map(x,y)=c:/* マップ
            map0(x,y)=c:/* 仮想画面
        next
    next
endfunc

/*****************************************************************
/* 汎用関数
/*****************************************************************

func srand2()
/* rand()乱数を初期化する
int tm=time()
    tm=tm and &h0fff
    tm=tm * 16
    srand(tm)
endfunc

func rand2(seed;int)
    return (rand() mod seed):/* 0~seed-1の乱数を発生
endfunc

/*****************************************************************
音声ファイル入り圧縮ファイル: XBbs.zip

2013年3月4日月曜日

SHIFT-JIS文字ほぼ全一覧表示(SHIFT-JIS版)

X68000がサポートしていたSHIFT-JIS文字ほぼ全てを一覧表示します。
こちらは内部処理が全てSHIFT-JISですが、正常に動きます。
強制SHIFT-JISモードをオンに設定して実行してください。
// SHIFT-JIS版(強制SJISモード)
/* SHIFT-JIS 全文字コード表示プログラム 
// テキスト画面がスクロールできないのでページ切り替え
    font("Migu 1M")
    int fzenhan:// YES=
    width(64,,fzenhan)
    print "fzenhan=";fzenhan
    cls()
    
    if isLocalizeJapan() then {
        setFunctionKey(0,"次へ",&h0d)
        setFunctionKey(1,"中断",&h1b)
        print "半角文字"
    } else {
        setFunctionKey(0,"Next",&h0d)
        setFunctionKey(1,"Break",&h1b)
        print "Half-Width Character"
    }
    print_code0(fzenhan)
    //
    displayFunctionKey(YES,0,1)
    //
    while YES
        if print_code(&h8100,&h9fff) then break
        if print_code(&he000,&hefff) then break
        print_head()
        break
    endwhile
    //
    // ファンクションキー表示は個数を変えても自動的に前の表示は消えないので、ユーザーが消す必要がある(そうしないと表示が重なる)
    displayFunctionKey(NO,0,1)
    if isLocalizeJapan() then {
        setFunctionKey(0,"終了",&h0d)
    } else {
        setFunctionKey(0,"End",&h0d)
    }
    displayFunctionKey(YES,0,0)
    int ky
    repeat
        ky=inkey()
    until ky<>0
end

//--------------------------------

func print_head()
    if fzenhan then {
        print "-code-:-+0-+1-+2-+3-+4-+5-+6-+7-+8-+9-+A-+B-+C-+D-+E-+F-"
    } else {
        print "-code-:-0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F-"
    }
endfunc

func print_skip()
    print "      :                                                "
endfunc

func str hex4$(h;int)
    return (right$("0000"+hex$(h),4))
endfunc

func str hex2$(h;int)
    return (right$("00"+hex$(h),2))
endfunc

func printChr(h;int,l;int)
    print chr$((h shl 16)or l);
endfunc

func int print_code(st;int,ed;int)
/* 全角文字表示 
int i,li,hi
int j
    for i=st to ed
        hi=i / 256
        li=i mod 256
        if li=0 then {
            print_head()
            int ky
            repeat
                ky=inkey()
            until ky<>0
            if ky=&h1b then return (YES)
            cls()
            if isLocalizeJapan() then {
                print "全角文字"
            } else {
                print "Double-Width character"
            }
            print_head()
        }
        if li<&h40 then continue:/* 下位8ビットが<$40の文字はない 
        
        /* アドレス表示 
        print " ";hex4$(i);" :";
        for j=0 to 16-1
            print " ";
            int c=(i+j) and &hff
            if c<&h40 or c=&h7f or c>=&hfd then { :/* 未定義文字 
                if fzenhan then {
                    print "**";
                } else {
                    print "*";
                }
            } else {
                c=(i+j)
                print chr$(c);    :/* 途中で桁上がりを起こさないことを前提にした処理 
            }
        next
        print
        i=i+16-1:/* 次のnext +1されるから
    next
    return (NO)
endfunc

func print_code0(fzenhan;int)
/* 半角文字表示 
int li
int j,c
    print_head()
    for li=&h20 to &he0-1
        /* 途中表示しないエリア 
        if li=&h80 then print_skip()
        if li>=&h80 and li<=&h9f then continue
        
        /* アドレス表示 
        print "  ";hex2$(li);"  :";
        /* 文字表示
        for j=0 to 16-1
            print " ";
            c=li+j
            if c=&h7f or c=&ha0 then c='*'
            print chr$(c);
            if fzenhan then print " ";:/* 全角=半角*2のフォントの時は後ろにスペースを入れる
        next
        print
        li=li+16-1:/* 次のnext +1されるから
    next
endfunc

Zipファイル :XBetc.zip

2013年3月1日金曜日

モーション関数テスト

モーション関数のテストプログラムです。 本体を傾けるとその情報を表示します。
//----------------------------------------------------------------------------------------------
// motion test
//----------------------------------------------------------------------------------------------

print "versionXBiOSMotion$=";versionXBiOSMotion$()

setFunctionKey(0,"end"   ,'!')
setFunctionKey(1,"pause" ,'p')
setFunctionKey(2,"start" ,'s')
setFunctionKey(3,"clear" ,'c')
setFunctionKey(4,"degree",'d')
setFunctionKey(5,"veloc" ,'v')
setFunctionKey(6,"rotate",'r')
displayFunctionKey(YES,0,6)
kBackgroundAlpha(0.9)

int mode=MOTION_DEGREE
if motionStart(10,mode) then {
    print localizedString("モーションは使えません","Can't use motion.")
    end
}
printMode(mode)

float x,y,z
int ky,cnt,i

while YES
    if not kbhit() then {
        i=0
        cnt=motionCount()
        if cnt>0 then locate(0,1):print "cnt=";cnt
        while cnt>0
            x=motionGetRotation(y,z)
            locate(0,2+i)
            if mode=MOTION_ROTATION then {
                if isLocalizeJapan() then {
                    print using "左右=+#.####,上下=+#.####,方位=+#.####";x,y,z
                } else {
                    print using "pitch=+#.####,roll=+#.####,yaw=+#.####";x,y,z
                }
            } else {
                if mode=MOTION_DEGREE then {
                    if isLocalizeJapan() then {
                        print using "角度:x=+##.####,y=+##.####,z=+##.####";x,y,z
                    } else {
                        print using "degree:x=+##.####,y=+##.####,z=+##.####";x,y,z
                    }
                } else {
                    if isLocalizeJapan() then {
                        print using "角速度:x=+##.####,y=+##.####,z=+##.####";x,y,z
                    } else {
                        print using "velocity:x=+##.####,y=+##.####,z=+##.####";x,y,z
                    }
                }
            }
            cnt=cnt-1
            i=i+1
            if kbhit() then break
        endwhile
    } else {
        ky=inkey()
        switch ky
            case 'p'
                motionPause(YES)
                print "Pause"
                break
            case 's'
                motionPause(NO)
                print "Start"
                break
            case 'c'
                cls()
                motionClear()
                break
            case 'd'
                mode=MOTION_DEGREE
                motionSelectData(mode)
                cls()
                motionClear()
                printMode(mode)
                break
            case 'v'
                mode=MOTION_VELOCITY
                motionSelectData(mode)
                cls()
                motionClear()
                printMode(mode)
                break
            case 'r'
                mode=MOTION_ROTATION
                motionSelectData(mode)
                cls()
                motionClear()
                printMode(mode)
                break
            default:
                // 念のため / just in case
                beep()
                break
        endswitch
        if ky='!' then break
    }
endwhile
motionEnd()
end

//----------------------------------------------------------------------------------------------

func printMode(mode;int)
    locate(0,2)
    if mode=MOTION_DEGREE   then print localizedString("角度     ","DEGREE  ")
    if mode=MOTION_VELOCITY then print localizedString("角速度   ","VEROCITY")
    if mode=MOTION_ROTATION then print localizedString("オイラー角","EULER   ")
endfunc

func str localizedString(js;str,es;str)
    if isLocalizeJapan() then return(js)
    return (es)
endfunc

//----------------------------------------------------------------------------------------------

Zipファイル :XBtests.zip