【MSX】MSX-BASICの研究(1) 条件分岐ロジック
この記事について
MSX-BASICでプログラムを書いていて思い出すのが、昔ベーマガでDr.Dが「論理式を使うのじゃ」と口を酸っぱくして言っていたこと。
確かに論理式を使うとIF文は無くなるが、しかし、論理式は本当に速いのだろうか?
というのも、ネットでBASICの高速化テクニックを探していたところ、ON〜GOTO〜を使うほうが速い、という記事を見つけたためで、本当はどれが速いのだろうか?と考えた次第。
それじゃあ実際に比較してみようか、というのがこの記事の趣旨になります。
今の時代にどれだけの人が必要としている情報なのかわかりませんが(汗
※(2021/8/9)パターン4として、移動量を配列変数に定義した場合をテストしてみました。
記事の最後に追記しています。
テスト方法
今回のテスト方法は、以下の方針としています。
- WebMSXで実施。
- 一般的に使用される、SCREEN 1、WIDTH 32、DEFINT A-Zで初期化した状態で実行する。
- ロジックは、実際の実装を考慮して4方向の判定処理とする。
- カウントダウン終了から画面右端までの移動時間を測る。
パターン1
素直に入力値をIF文でひとつひとつ判定していくコードです。
プログラムリスト
100 ' ******************************* 110 ' CHARACTER MOVE LOGIC TEST 1 120 ' ******************************* 130 ' *** COMMON INITIALIZE *** 140 SCREEN 1:WIDTH 32:DEFINT A-Z 150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START" 160 X=0:Y=10:TM=TIME 200 ' *** LOGIC *** 210 S=STICK(0):VX=0:VY=0 220 IF S=1 THEN VY=-1:GOTO 260 230 IF S=3 THEN VX=1:GOTO 260 240 IF S=5 THEN VY=1:GOTO 260 250 IF S=7 THEN VY=-1 260 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A"; 270 IF X<32 GOTO 200 300 ' *** RESULT *** 310 LOCATE 0,1:PRINT "TIME="; TIME-TM 320 END
実行結果
パターン2
ON〜GOTO〜で分岐させるコードです。
プログラムリスト
100 ' ******************************* 110 ' CHARACTER MOVE LOGIC TEST 2 120 ' ******************************* 130 ' *** COMMON INITIALIZE *** 140 SCREEN 1:WIDTH 32:DEFINT A-Z 150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START" 160 X=0:Y=10:TM=TIME 200 ' *** LOGIC *** 210 S=STICK(0) 220 ON S+1 GOTO 270,230,270,240,270,250,270,260,270 230 VX=0:VY=-1:GOTO 270 240 VX=1:VY=0:GOTO 270 250 VX=0:VY=1:GOTO 270 260 VX=-1:VY=0:GOTO 270 270 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A"; 280 IF X<32 GOTO 200 300 ' *** RESULT *** 310 LOCATE 0,1:PRINT "TIME="; TIME-TM 320 END
実行結果
パターン3
論理式を使ったコードです。
プログラムリスト
100 ' ******************************* 110 ' CHARACTER MOVE LOGIC TEST 3 120 ' ******************************* 130 ' *** COMMON INITIALIZE *** 140 SCREEN 1:WIDTH 32:DEFINT A-Z 150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START" 160 X=0:Y=10:TM=TIME 200 ' *** LOGIC *** 210 S=STICK(0) 220 VX=(S=7)-(S=3) 230 VY=(S=1)-(S=5) 240 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A"; 250 IF X<32 GOTO 200 300 ' *** COMMON RESULT *** 310 LOCATE 0,1:PRINT "TIME="; TIME-TM 320 END
実行結果
比較結果
結果は以下のようになりました。
パターン | 処理方法 | 処理時間 |
---|---|---|
1 | IF文のみ | 56 |
2 | ON〜GOTO〜 | 51 |
3 | 論理式 | 59 |
総括
ON〜GOTO〜で処理するのが一番速いですね。実際にテストしていても、体感できるくらいに違いました。
また、パターン3の論理式がパターン1のIF文のみより遅かったという結果は、ちょっと意外でした。
しかし、パターン1のプログラムを見ていただけるとわかりますが、IF文で判定とは言え、条件に合致したときに他のIF文に入らないようにGOTOで飛ばしていますので、速くなっていたのでしょう。
論理式ではすべての値を評価する必要があるので、全てのIF文を実行しているのと同じことになっているのだと考えます。
実際、パターン1で各IF文のGOTOを書かなかった場合、処理時間は64と最も遅い結果になっていました.。
プログラムで条件分岐書く時は、ON〜GOTO〜で書けるように変数の値も考えると良いですね。
また気になる事があったら、検証してみたいと思います。
※2021/8/9 追記
パターン4
入力に対する各方向への移動量を配列変数に定義したコードです。
プログラムリスト
100 ' ******************************* 110 ' CHARACTER MOVE LOGIC TEST 4 120 ' ******************************* 130 ' *** COMMON INITIALIZE *** 140 SCREEN 1:WIDTH 32:DEFINT A-Z 142 DIM VX(9),VY(9):FOR I=0 TO 8:READ VX(I),VY(I):NEXT I 144 DATA 0,0,0,-1,0,0,1,0,0,0,0,1,0,0,-1,0,0,0 150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START" 160 X=0:Y=10:TM=TIME 200 ' *** LOGIC *** 210 LOCATE X,Y:PRINT " ";:S=STICK(0):X=X+VX(S):Y=Y+VY(S):LOCATE X,Y:PRINT "A"; 220 IF X<32 GOTO 200 300 ' *** COMMON RESULT *** 310 LOCATE 0,1:PRINT "TIME="; TIME-TM 320 END
実行結果
比較結果
パターン4を含むと、以下の結果になりました。
パターン | 処理方法 | 処理時間 |
---|---|---|
1 | IF文のみ | 56 |
2 | ON〜GOTO〜 | 51 |
3 | 論理式 | 59 |
4 | 配列変数 | 43 |
配列変数が抜き出て速いですね。
パターン1や2にあるGOTOが無いのでこの結果になったのだと考えます。
BASICはインタプリタ言語なので、命令数が1つ増えただけでも処理速度に影響するというのは認識ありましたが、実際に結果を見ると相当違いますね。
なお、このテストでは、座標の上限値/下限値を1方向しか判定していないので、実際にゲームに組み込んだ場合の性能とは異なります。
あくまで指標として捉えていただけると幸いです。
【MSX】GitHubに置いた.dskファイルをWebMSXで実行する方法
今日書いたこちらの記事の補足です。
最初、WebMSXでGitHubに置いた.dskファイルを読めなかったので、フリーのWebサーバに.dskファイルを置いていたのですが、URLパラメタの指定方法を見直したらGitHubの.dskファイルでも実行できましたので、書いておきます。
具体的には、以下のように指定します。
https://webmsx.org/?MACHINE=MSX1J&DISKA_URL=<対象の.dskファイルのURL>&FAST_BOOT
「DISKA_URL」パラメタで与えるのがミソです。
なお、最後の「FAST_BOOT」は気持ち起動が速くなるようなので付けていますが、任意です。(この指定の仕方でいいのか自信がない…)
そして、この「DISKA_URL」に与える「対象の.dskファイルのURL」ですが、GitHubで対象の.dskファイルのページにある「Download」ボタンのURLになります。
このボタンを右クリックした「URLをコピー」することで取得したURLを指定してください。
他、多数のオプションを指定できますが、詳細は以下のGitHubリポジトリのドキュメントを参照してください。
ちなみに、使用する.dskファイルがあるリポジトリは、publicにしておいてくださいね。
ではでは。
【MSX】BLOCK BREAKER
唐突ですが、MSX-BASICの練習で、ブロック崩しゲームを作ってみました。
(ボールの挙動が若干怪しいのと、パドルの移動にイライラしますが…)
以下のURLで遊べます。
(※GitHubの.dskをWebMSXに直接渡せたので、URLを変更しました)
しばらく待って、タイトルが出たらSPACE or Aボタンでスタート。
カーソルキー or コントローラの左右でパドルを動かしてボールを落とさないようにして、ブロックを壊してください。
ボールを3回落とすとゲームオーバーです。
githubでもソースとディスクイメージ、某雑誌風のドキュメントを公開しています。 詳細については、こちらのドキュメントを参照してください。
このプログラムを元にアセンブラ化していきたいと思っていますが、小数点の計算をどうするかな…
ではでは。
【git】GithubにSSH接続する
Githubのリポジトリへのアクセスは、主にhttpsとSSHがある。
一度cloneするだけであればhttps接続で問題ないが、GitHubではSSH接続が推奨されており、アクセスするたびにユーザー名とアクセストークンを入力することも不要になるため、普段から利用するリポジトリへのアクセスはSSHが望ましい。
このSSHの設定方法については既に多数の記事が存在するが、ようやく自分の中で手法が固まったので、まとめ直したものを記載する。
0. SSHキー生成の準備
基本的に、1つの端末に1つ作成するイメージで良いと思う。
Windowsの場合は自分のホームディレクトリに.sshフォルダを作成後、スタートメニューからGit Bashを起動する。
Linuxの場合は、ホームディレクトリでそのまま作業を行う。
1. SSHキー生成コマンド
以下のコマンドを実行する。
$ ssh-keygen -t rsa -C <メールアドレス>
作成先のディレクトリの確認。
デフォルトで問題ないため、そのままEnter
を押す。
Enter file in which to save the key (/c/Users/hitoshi/.ssh/id_rsa):
作成先に既に作成されている場合は以下のメッセージが表示される。
上書きして良いならy
を入力する。
/c/Users/aburi/.ssh/id_rsa already exists. Overwrite (y/n)?
続いてパスフェーズの入力を求められる。
何も入力せずEnter
を入力する。
Enter passphrase (empty for no passphrase): Enter same passphrase again:
パスフェーズを設定するとVS Codeからのpush/pull操作が上手くいきませんでした。
回避方法があると思われますが、個人利用であれば未設定で構わないと思います。
以下のメッセージが表示され、公開鍵が生成される。
Your identification has been saved in /c/Users/hitoshi/.ssh/id_rsa. Your public key has been saved in /c/Users/hitoshi/.ssh/id_rsa.pub. The key fingerprint is: SHA256:<暗号化文字列> The key's randomart image is: +---[RSA 2048]----+ | +o*o | | . *.=. | | O o | | + = = | | .. * o S | |+..+ + = + | |==o . + = | |#... ..o.. | |@O ... E | +----[SHA256]-----+
後半のランダムアートの内容は、生成するごとに変わります。
2. 作成結果確認
.ssh
ディレクトリにid_rsa.pub
が存在していれば成功。
$ ll total 6 -rw-r--r-- 1 hitosh i 197121 1671 2月 3 01:51 id_rsa -rw-r--r-- 1 hitoshi 197121 401 2月 3 01:51 id_rsa.pub -rw-r--r-- 1 hitoshi 197121 405 2月 3 01:35 known_hosts
3. Githubに公開鍵を登録
生成した公開鍵の内容をコピーする。
id_rsa.pub
をテキストエディタで開き中身をコピーするか、以下でコンソールに出力したものをコピーする。
$ cat ~/.ssh/id_rsa.pub
$ clip < ~/.ssh/id_rsa.pub
githubのアカウントの「Settings」ページを開き、「SSH and GPG keys」を選択、「SSH keys」の右側にある「New SSH key」ボタンを押す。
名前は適当に、「<端末名>@<OS名>」のようにすると良いかもしれない。
4. GithubとのSSH接続確認
接続の確認は以下で行う。
$ ssh -T git@github.com
成功すると以下のメッセージが表示される。
Hi <ユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.
5. トラブルシューティング
失敗した場合は、以下を確認する。
1. そもそもネットワークに接続されているか。wifiや有線LANの接続を確認する。
2. Githubに登録したSSH公開鍵の内容。一度削除して登録しなおしてみる。
3. ssh公開鍵の作成内容。暗号化方式が誤っていないかなど。一度.ssh
ディレクトリ内のファイルを削除し、再度作り直してみる。
【Obsidian】Obsidianのモバイルアプリを試してみた
Obsidianは動作が軽く使いやすい、マークダウン形式で記述するメモアプリだが、これまでモバイルデバイス向けのアプリケーションが存在しなかった。
そのため、個人的にはAndroidのGitJournalというアプリを使用してきたが、見た目や操作感が違うためあまり快適とは言えず、またまともに使うためには課金が必要(しかもサブスクのため払い続けなければならない)であるため、活用できていなかった。
しかし、ようやくObsidianのモバイルアプリが2021/7/12にリリースされた。
早速試してみたので、所感などを記しておく。
この記事は導入した時点でのものになります。
今後本格的に使用し、細かいことが判明次第、加筆修正していきます。
ファーストインプレッション
軽く触ってみた感想。あくまで個人的な感想です。
- 動作も軽く、デスクトップ版の雰囲気そのままで使える。
- ただし、操作が若干複雑。これは設定で何とかなるのか。
- テンプレートの場所、日付書式、プラグインといった設定については、デスクトップアプリの設定を参考に設定しなおさなければならない。
- 多言語対応がまだされていない。ただ、デスクトップアプリを使用していればそれほど困らず、そのうちサポートもされることだろう。
- PCでObsidianを使っている人なら、データ同期の問題を何とかさせてでも使った方がいい。
データの同期について
「なんとかしてデータ同期させて」と書いたのは、Obsidianがローカルにデータを保持するアプリケーションであり、単体ではクラウドストレージに対応していない為である。
ここでは、現状選択肢として選択可能なクラウドストレージサービスと、簡単な概略を記載する。
Obsidianのモバイルアプリのみを使う人はこの限りではありません。 たとえばタブレット端末でしか使わない、というのもアリで、その場合は単純にValutを作成するだけになります。
obsidian sync
obsidianオフィシャルの同期サービス。
プラグインでサポートされているため、OSやデバイスを意識せずに使える。
また、Obsidian publishというWeb公開サービスも使用できる。
有料となっているが、ヘビーに使いたい場合は選択肢に入れても良いかもしれない。
git(github)
デスクトップ版では「Obsidian git」というサードパーティープラグインがあり、githubを介して複数PC間のデータ同期ができていた。
しかし、スマートフォン(自分の場合はAndroid)ではこのプラグインがサポートされていない。
また、gitクライアントアプリもあるが、手動でpush/popする必要があり、操作性に欠ける。
そのため、今回はgitの使用を見送ることとした。
手動でgitリポジトリからpopする運用で良ければ、この手段でも問題ないです。
google drive
PC(Windows)では、googleドライブアプリを入れることで、クラウドであることを意識せずに使える。
Androidでは、google製の「ドライブ」はクラウドストレージの中を見るだけでローカルとの同期は取れず、個別にファイルをダウンロードするしかない。
この目的を達成するものとしては「FolderSync」や「Autosync」というアプリがある。
なお、ubuntu(Linux)での使用については、google製のアプリがリリースされていないため環境駆逐の問題が残るのと、googleはサービス自体に突然大きな仕様変更を行う不安定さがあるのが難点。
Linuxでのgoogleドライブのマウントは、google-drive-ocamlfuseというアプリケーションでマウント可能になる模様。
これについては別記事にしようと思います。
OneDrive
PC(Windows)の操作感はgoogle Driveと同様、クラウドであることを意識せずに使える。
Androidは「FolderSync」というアプリでクラウド上(OneDrive)のファイルと端末のディレクトリ(任意指定可能)の同期をとることができるらしい。
らしい、というのは私がこのアプリ(FolderSync)を使用していないから。レビューを見ると不安定なようだったので、見送りました。
また、Microsoftのサービスであるためgoogleほどの不安は無いが、ubuntu(Linux)ではまだMicrosoft製のアプリがリリースされていないため、google driveと同様に環境構築の問題がある。
Dropbox
過去はクラウドストレージの筆頭となるサービスだったが、無料での利用台数が3台まで、他のストレージに比べて容量が少ないといった使い勝手の悪さと、有料の価格設定の高さから、ヘビーユーザーにはお勧めできない。
しかし、公式にubuntu(Linux)への対応を行っていること、モバイル端末でのアプリも様々なものがあるため、利用台数が少ない場合(PC1台、モバイル端末1台など)は、Dropboxを選択するのはアリだと思う。
その他
その他のサービスも同様で、使用しているOSとモバイルデバイスでのサポート状況を確認し、問題なければ使用できる。
問題がある、ないの判断は「ローカルとクラウドでデータが自動的に同期できるか」で良いと思う。
FAQ
Valut(書庫)を開こうとするとエラーが発生して開けない
SDカードのディレクトリをValutに指定したのが原因。
本体ストレージにディレクトリを用意すること。
バージョン 1.0.3時点。
恐らくSDカードへのアクセス権限付与漏れで、将来的に解消されると思われる。
エディタの文字サイズが大きい
プレビューは普通なのに、エディタに入ると文字が大きくなる。
これは設定メニュー(歯車のアイコン)から「Appearance」に入り「Font size」で指定できる。
指定後は、一度アプリを終了させること。
【Python】Pythonの仮想環境を使う
例えば、複数のアプリケーションを開発していて、導入パッケージがそれぞれ異なる場合、各アプリケーションで最低限必要なものだけを導入した環境が欲しくなることがある。
また、Pythonの基本的なバージョンは上げつつ、開発中のアプリケーションは特定のバージョンに固定したいことがある。
このようなときは、Pythonの仮想環境を使用し、Pythonのバージョンと導入パッケージをアプリケーションごとに固定する。
ここでは、Python標準機能として用意されているvenv
を使用する。
仮想環境の作成
バージョンを指定せずに作成
プロジェクトのルートディレクトリで以下を実行する。
(以下は仮想環境名を.venv
とした場合)
python -m venv .venv
こうすることで、パスが通ったPythonのバーションで作成される。
Linuxなどの場合は、
python
コマンドではなくpython3
コマンドの場合があります。 ubuntu20.04だとpythonコマンドで大丈夫です。
仮想環境のバージョンを指定する(Windows)
WIndowsの場合はpy
コマンドがあるので、プロジェクトのルートディレクトリで以下を実行する。
py -3.6 -m venv .venv
最初の引数(-3.6
)は、Pythonのバージョンとなる。
仮想環境のバージョンを指定する(mac、Linux)
mac、Linuxの場合は、pyenv
を使うのが良さそう。
githubに公開されているので、インストールする。
使い方などは以下を参照。(そのうち追記します)
参考
[https://www.mathpython.com/ja/ubuntu-python/:embed:cite]
仮想環境の使用
Windows(コマンドプロンプト、PowerShell)の場合
プロジェクトのルートフォルダで以下を実行する。
./.venv/Scripts/activate
Mac、Linuxの場合
プロジェクトのルートディレクトリで以下を実行する。
source ./.venv/bin/activate
運用
仮想環境でパッケージをインストールする
以下コマンドを実行することで、その仮想環境にパッケージが導入される。
pip install [package name]
仮想環境に導入されているパッケージを確認する
仮想環境に切り替え後に以下コマンドを実行する。
pip freeze
仮想環境を配布する
venv
したディレクトリをそのまま渡すのではなく、各端末で仮想環境を作成しパッケージを導入する方法をとる。
まず、配布元で導入するパッケージのリストを作成する。
pip freeze > requirement.txt
作成されたrequirement.txt
を配布し、構築する端末では以下コマンドでパッケージを導入する。
pip install -r requiments.txt
切り替え後のPythonのバージョンを確認する
仮想環境に切り替え後に以下コマンドを実行する。
python -V
※V
は大文字
仮想環境を終了する
Windows、Mac、Linux共に、以下のコマンドを実行する。
deactivate
仮想環境を削除する
作成されたディレクトリを削除するだけ。
所感
pip freeze > requirements.txt
をする際に余計なパッケージを含めたくないときなどは、同じpythonバージョンでも別環境を作った方が良い。
また、複数の環境が作れるので、例えば古いバージョンでバグ報告があった場合の検証環境も簡単に用意できる。
OSごとに若干操作方法が異なるが、標準で使えてお手軽だし、とても便利なので、個人開発でも積極的に使っていきたいと思う。
【Python】PyInstallerの警告に対する対処方法について
環境
発生した環境は以下。
発生事象
上記環境にて、pyxelpackagerでアプリケーションの単体実行ファイル生成時、以下警告が発生。
単体実行ファイルが作成されない。
12467 WARNING: Tcl modules directory /usr/share/tcltk/tcl8.6/../tcl8 does not exist.
原因
pyxelpackagerでは、引数(アセット、実行ファイル)を作成する処理のみを行い、PyInstallerに渡す。
単体実行ファイルを作成する処理はPyInstallerにて行われるが、このPyInstallerでのパスの指定がおかしい。
(tcl8ディレクトリはtcl8.6の下に存在しているが、その上の階層を参照しようとしている)
対処
~/.local/lib/python3.8/site-packages/PyInstaller/hooks/hook-_tkinter.py の 206行目に余計な引数が指定されているのを削除。
(修正前)
206 modules_path = os.path.join(tcl_root, "..", modules_dirname)
(修正後)
206 modules_path = os.path.join(tcl_root, modules_dirname)
その後、pyxelpackagerを実行すると、単体実行ファイルが作成された。
補足
venvで仮想環境を作成している場合、修正対象ファイル(hook-_tkinter.py)は以下に配置される。
./lib/python3.8/site-packages/PyInstaller/hooks/hook-_tkinter.py
なお、Macは手元に環境が無いため未確認だが、恐らく同様の原因だと思われる。