プチコンで遊ぼう! (はてなブログ版)

任天堂3DSのプチコンで遊ぼう! [twitter:@eida_s]

はてなダイアリーから移行しました。 はてなダイアリーのURLを開いても自動的にこちらにリダイレクトされますのでご了承ください。

プチコン3号/BIGのランチャー

メモ

MOTさん LINE LAUNCHER
http://motmark3.web.fc2.com/petitcom3/mot3llc.html

みむさん みむめにゅ~

画面の横に表示可能な文字数を調べる

PEPの中のMOREを作る過程で得た知見です。

画面の横に表示可能な文字数を調べる方法を紹介します。

XSCREENで表示解像度を変えることができますが、現在設定されているXSCREENを取得する方法が現在ないため、現在の解像度が何かはわかりません。
テキストで画面の横1行に表示可能な文字数についても同様にわかりませんでした。

これについては、以下のようにして調べられることがわかりました。
仮に画面が50×30文字表示の状態だとします。
この時、本来LOCATE文で表示可能な範囲は(0,0)~(49,29)です。
ところが(50,0)を指定してPRINTすることができるのです。
そして、そうした時、実際には(0,1)の位置に文字が表示されます。
これを利用してCSRXを調べると、画面横1行に表示可能な文字数を調べることができます。

これを応用して3号およびBIGの全スクリーンモードにおいて画面横1行に表示可能な文字数を調べることが可能な関数が次のようなものになります。

f:id:eidaht:20170609000007j:plain

PEPの中のMOREに実装されていますので、ソースコードを見てみてください。
PEPはこちらを見てください。
eidaht.hatenablog.com


さて、横幅はわかりましたが縦の行数は?
これは次の方法でわかります。
画面上から下に1行ずつPRINTとしていきます。するとどこかでスクロールが発生します。
スクロールが発生すると、その発生前と同じ位置にCSRYがセットされていますから、PRINTの前後でCSRYが変わらなかった時、最大の行数となります。
MOREもこの考え方で実装しています。
ソースコードを参考にしてみてください。

プチコンデータ交換プロトコルPEPとデモプログラムを作りました

プロジェクト名: PEP

公開キー: NDHE33Y3 VKK8N5GY

公開日: 2017/06/11 2017/06/07

バージョン: 1.00

v1.00 初公開
(2017/06/11 --README--を単品で実行してメッセージ読めるようにした)

プチコンのプログラム間でデータ交換を行うためのプロトコルPEPの提案とその実装、およびそのデモプログラムを作りましたので公開です。

スマイルツールはスロット4で実行されるため、プログラム間でデータをやりとりする方法はファイルへの読み書きくらいしかありません。

PEPは、クリップボードをスタックのようにして使うことで、プログラム間でデータをやりとりすることを可能にします。

使い方の例としては、お絵かきプログラムからファイル選択を行う別プログラムを呼び出して、どのファイルが選択されたかを戻してもらう、などの使い方があります。

PEPの詳しい説明は、プロジェクトの中のファイルPEPの中をご覧ください。

デモプログラムとして、PCUIを用意しましたので、実行してみてください。
UNIX風のプログラムを連続実行するCUIの実行環境です。
例として、「FSEL | CAT | HEAD 15 | NL | PRINT」などと入力して実行してみてください。
それぞれのコマンドは別プログラムですが、パラメータをやりとりして連続実行されます。

f:id:eidaht:20170607222537j:plain

よければ、各プログラムのソースを見てみてください。


【PEP 今後の課題】
・PEPの仕様をブログにアップする
・PEPライブラリをプロジェクトをまたいだ実行が可能なようにバージョンアップする

標準のグラフィックエディタ(SBGED)に機能追加してみた

標準のグラフィックエディタ(SBGED)に、GSAVEデータをDATA文にして書き出す機能を追加してみました。

f:id:eidaht:20170515011029j:plain

ファイル名: SBGED

公開キー: 4RQ5438D

公開日: 2017/05/15

バージョン: 1.71 (標準のv1.7を基準にしている)


標準のグラフィックエディタ(SBGED)に次の機能を追加したものです。

・GSAVEデータをDATA文にして書き出す機能
スプライトのGRPをほんのちょっと直しただけなのに、GRP全体を配布するのは仰々しい...、というときに使える機能です。
GSAVEのデータをDATA文として出力してくれます。

【使い方】
①SBGEDが起動したら、COPYモードにして範囲選択します。
②Yボタンを押します。「フォント読み込み」となっていたところが「そのほかの機能」と表示されます。
③さらにYボタンを押します。使える機能が表示されます。
④Yボタンを押して「GSAVEデータ出力」の機能を起動します。
⑤出力先のスロットを聞いてくるので、上下でスロットを選択してAボタンで決定します。
⑥指定したスロットに、DEF文とDATA文が出力されます(画像参照)。
 DEF GLOAD_G04_001となっていたら、プログラム本体で「GLOAD_G04_001」を呼び出すとGRPへの書き込みを行います。
 スプライトやBGの定義に対して使うことを想定していますが、他のGRPに書き込みたい時は、DEF文中のGP,X,Yのあたりを適宜書き換えてください。

プチコンプログラミング覚え書き(7) 互換機能編

プチコンBIGも発売されたので、「3号プログラミング覚え書き」でなくて「プチコンプログラミング覚え書き」にしました。

バンナムDLCを使っているプログラムを一つのソースコードでBIGやDLCの入っていない3号で動かすには

 DLCが入っているか入っていないかは、FILESやCHKFILEでDLCのフォルダを調べることでチェックできます。
 例えば、パックマンDLCの場合、FILES "$PACMAN"とするとDLCが入っていればそのフォルダ名が返ってきますし、DLCが入っていなければ何も返ってきません。
 プチコン3号だけの時はこれでOKでした。

 ところが、プチコンBIGでは、FILES "$PACMAN" のように $ を含むフォルダ名/ファイル名をFILESやCHKFILEに指定すると、Illegal function callエラーになってしまいます。

 そのため、プチコンBIGを含めて対応するには、上記のチェックをするのに先だって、システム変数HARDWAREをチェックしておきます。

 具体的な方法は次のソースコードのとおりです。

VAR DLCNAME$="PACMAN"
IF HARDWARE<2 THEN
 IF CHKFILE("$"+DLCNAME$+"/DEFS") THEN
  DLCOPEN DLCNAME$
  'その他のDLCを使う処理....
 ENDIF
ENDIF

認知心理学の実験 on プチコン3号

以前、プチコンmkIIで作った認知心理学の実験をプチコン3号用に焼き直しました。

キー: EB2X5EKE
公開日: 2016/11/03

mkII時代の動画を貼っておきます。
なお、今回作ったのは、動画のうち実験2の方だけです。
www.youtube.com

補足: ほしけんさんのプチコン漢字ライブラリの高速化を試みた

「ほしけんさんのプチコン漢字ライブラリの高速化を試みた」のエントリの補足(兼自分用メモ)。
eidaht.hatenablog.com

「ほしけんさんのプチコン漢字ライブラリの高速化を試みた」でキャッシュなどを導入してプチコン漢字ライブラリの高速化を行いましたが、いくつか注意点と今後の改良点を。
改造版プチコン漢字ライブラリを以後はKNJLIB_MOD1と表記します。


■注意点1.KNJLIB_MOD1ではメモリ使用量に注意が必要

オリジナル版ではプログラム内リソースを使っているので、ライブラリがロードできればメモリが足りなくなる、ということはないように考えられています。
しかし、KNJLIB_MOD1では参照表に512キロバイトほどの配列を使い、さらにキャッシュ用として動的に拡張する配列を使います。
(キャッシュ用は、16x16フォントでキャッシュサイズが初期状態の300文字の場合、300キロバイト)。

つまり、オリジナル版は、使う側はライブラリの中身をよくしらなくてもブラックボックスとして使えるように設計されていますが、
KNJLIB_MOD1の方は使用するメモリ量を意識しておく必要があります。
(もちろんほとんどケースでは何も考えなくてもメモリが不足することはないと思いますが...。)

さもないと、単純にオリジナル版を置き換えたらメモリ不足で止まってしまった、ということが起こりえます。


■注意点2.パフォーマンス重視の場合、キャッシュを最適化する

KNJLIB_MOD1でパフォーマンス重視の設定にしたい場合は、キャッシュを最適化した方がよいです。
キャッシュは、決められたキャッシュサイズがあり、キャッシュサイズ一杯の状態で新たな文字を読み込むと、最も長く使われていなかった文字をキャッシュから追い出して新たな文字を追加します(いわゆるLRU法)。
この追い出しが発生すると処理に時間がかかってしまいます。
また、キャッシュされている文字がいつ使われたかを覚えておくための領域があり、キャッシュが使われるたびにこれを更新するので、ここでも若干の時間がかかります。
これらのことから、最もパフォーマンスを発揮できるのは、プログラム内で使う文字をすべてキャッシュに収め、かつ、使った文字を覚えておく機能をオフにした時です。

これをできるように、設定用のCOMMON DEFを追加してあります。

・GKNJCACHESIZE
 使い方: 変数 = GKNJCACHESIZE(キャッシュサイズ)
 キャッシュサイズを設定します。
 キャッシュサイズの変更は随時可能ですが、すでに使っているキャッシュサイズよりも小さな値を設定しても、実際のキャッシュサイズは縮小しません。
 キャッシュサイズは、キャッシュに納める文字数を設定します。戻り値はキャッシュサイズを返します。
 キャッシュサイズをプログラムで使う全ての文字の種類より大きく設定するとキャッシュ追い出しが発生しないので、最もパフォーマンスを得ることができます。
 なお、キャッシュに使うメモリ使用量は、(フォント幅×フォント高さ×4×キャッシュサイズ)で計算できます。
 例えば、16x16ドットフォントでキャッシュサイズが300文字の場合、16×16×4×300=307200バイト=300キロバイトを使用します。

・GKNJCACHELRU
 使い方: 変数 = GKNJCACHELRU(TRUE または FALSE)
 使った文字を覚えておく機能のオン・オフを設定します。TRUEでオン、FALSEでオフとなります。
 使った文字を覚えておく機能をオンにしておくと、キャッシュを使うごとにLRUキューの先頭に使った文字を移動します。
 オフの場合、LRUキューの先頭への移動は起こりません。
 LRUキューがキャッシュサイズに達している時に、新たな文字がキャッシュに追加されようとすると、LRUキューの末尾の文字をキャッシュから追い出します。
 前述のキャッシュサイズを最適化して、キャッシュの追い出しが発生しないようにした場合、オフにしておくと若干速度が向上します。
 
!!! とここまで書いて、GKNJCACHELRUにバグがあることがわかりましたので後で直します。スミマセン。 !!!



■注意点3.フォントを切り替えているケースではかえって遅くなる場合がある

KNJLIB_MOD1では、キャッシュがフォントの切り替えに対応しておらず、フォントが切り替わった時に一旦すべてのキャッシュを捨てています。
また、構造上、キャッシュに入っていないフォントをキャッシュに追加するオーバーヘッドで若干時間がかかります。
このため、フォントを頻繁に切り替えている場合、キャッシュを捨てる処理と、フォントをキャッシュに追加するオーバーヘッドの分、オリジナル版より時間がかかることになります。
これに対する対策はフォントの切り替えを行わない、くらいしかありません。
ですが、これでは既存のプログラムに対応できないので、次の今後の改良点につながります。


■今後の改良点.キャッシュをフォント切り替えに対応する

上記注意点3に関する問題は、キャッシュ自体をフォントの数だけ持っておき、それを切り替えることで理論上対応可能です(さらにメモリ消費しますが...)。
そこで次のバージョンではフォント切り替えに対応したキャッシュシステムへの拡張を行います。
さらにメモリを消費するようになるため、これで万事解決、ではないですがとりあえず。

文字列を追加していく時はINCの方が速い

数値を加算する時は、INCを使うよりもA=A+Bのようにふつうの代入と加算の組み合わせの方が速い、という事実が以前から知られていましたが、文字列の時はどうなのか?と思い検証してみました。

以下のようなプログラムを実行します。
f:id:eidaht:20161016194338j:plain
最初のループが代入を使う場合、後のループがINCを使う場合です。

結果は以下のようになりました。
f:id:eidaht:20161016194614j:plain
A(ループを使う方)がB(INCを使う方)の2倍程度の時間がかかっていることがわかります。

何回か実行しても、AとBの順番を入れ替えても同じような結果になるので、ほぼ間違いなく、文字列の場合はA$=A$+B$のような代入よりも、INCの方が速いようだと思われます。
(単純に2倍とは言い切れませんが、それに近い程度の大きな差があります。)

ゲームでは大量(1000回とか)の文字列の連結はほぼ使わないのでどちらでも問題ないでしょうが、文字列を扱うツール系のプログラムでは使い勝手の差が出てくる可能性がありますので気を付けておくといいかも。

ほしけんさんのプチコン漢字ライブラリの高速化を試みた

ほしけんさんのプチコン漢字ライブラリ(KNJLIB)の高速化を試みてみました。

ほしけんさんのプチコン漢字ライブラリ(http://wiki.hosiken.jp/petc3gou/?Toukou%2F%A5%D7%A5%C1%A5%B3%A5%F3%B4%C1%BB%FA%A5%E9%A5%A4%A5%D6%A5%E9%A5%EA)
はプログラムサイズと高速性のバランスがよく、普通の用途には十分な処理速度が出ます。
特に、New3DSではほとんど問題にならないと言っていいでしょう。
私の場合、特殊用途(リアルタイム進行するクイズゲーム)で使うために速度的な制約が厳しいため、プチコン漢字ライブラリの高速化を試みてみました。

キー: 432XE37D

高速化のために改造した点は以下の3点です。
・文字テーブルの検索を、INSTRの代わりに最初に展開した参照表を使うようにした。
・フォントのビットマップをキャッシュするようにした。
・ビットマップテーブルを探す時の処理を若干書き直した。
これにより、オリジナル版に比べて大体5割ほど高速化されていると思います。キャッシュが効く状況ではさらに改善されます。

また、まとめwikiでスーさんが報告されていた、変数の宣言もれなども修正に入れています。


この改造版(「KNJLIB_MOD1」)では、巨大な配列を使いまくっているので、オリジナル版に比べて最低でも1メガバイト程度メモリを余計に消費します。
メモリの制約が厳しいプログラムの場合には使うのはむずかしいかもしれません。
なお、キャッシュサイズはバイト数ではなく、キャッシュする文字数(初期設定では300文字分)で設定するようになっているため、大きなフォントを使うとより大きくメモリを消費します。

オリジナル版のKNJLIBをそのまま置き換えてもほぼ問題なく動作すると思います。
少なくとも、オリジナル版に同梱されているサンプル3種類については、私が検証できる範囲での問題はみられませんでした。

配布時のファイル名は「KNJLIB_MOD1」となっていますので、名前を「KNJLIB」にしてオリジナル版と差し替えることで動作します。


この改造版を使うメリットとデメリットは以下のとおりです。

メリット
・Old3DSの場合、目に見えて高速化する

デメリット
・メモリを非常に多く使う
・初期化により多く時間がかかる
・プログラムの保守性が悪くなっている
New3DSだともともと速いので違いがわりづらい

別スロットの関数名/命令名

■ライブラリの直接呼びされることを想定しないDEFは、COMMON DEFにしないようにしよう

ライブラリとして呼び出したプログラムに、自分のプログラムと同じ関数名/命令名があると、Duplicate functionエラーになる。

SLOT 0

USE 1
?"A=";A()
?"B=";B()

DEF B()
 RETURN 1
END

SLOT 1

COMMON DEF A()
 RETURN B()
END

DEF B()
 RETURN 2
END

この結果は次のように表示される。(当然だが...)

A=2
B=1


仮にSLOT 1のDEF B()が、COMMON DEF B()になっていると、Duplication functionエラーになる。
ちなみにSLOT 0のDEF B()をCOMMON DEF B()にした場合もなぜか同様。
(SLOT 1からSLOT 0はUSEしていないので本来はエラーにならなくてもよさそうだが...)

結論としては、USEされたスロットは全部で一つの名前空間になり、COMMON DEFがある時、その名前と同じDEFが存在してはいけない、ということになる。

これを踏まえてライブラリプログラム作成時の注意事項を以下に書いておく。
以下では、ライブラリプログラムを呼び出すプログラムを「ホストプログラム」と呼ぶことにする。

ほしけんさんのプチコン漢字ライブラリ(KNJLIB)が広く使われるようになり、ライブラリプログラムの中に埋め込んで使うケースも出てきた。
さらにライブラリプログラムを利用したホストプログラムがあり、そのホストプログラムにもKNJLIBを埋め込んであるとする。

すると、ホストプログラム、ライブラリプログラムの両方にKNJLIBが埋め込まれていることになり、名前の衝突が起こってしまう。

この場合、ホストプログラム、ライブラリプログラム双方のKNJLIB部分のCOMMON DEFをDEFに変えることで名前の衝突を回避できる。

もちろんホストプログラム側の対応も必要だが、ライブラリプログラムを公開している方は上記を検討してみていただけると大変助かる。