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

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

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

140曜日計算とツェラーの公式

先日、ツェラー(zeller)の公式を使った140曜日計算をツイートしましたが、リスト写しまちがえで何度もツイートしなおしたので、最終版を掲載するのと、ツェラーの公式についての説明を載せておきます。

■140曜日計算

何度も修正ツイートしたのですが、最後にツイートしたものもM=M+(M<3)のところが(N<3)とかなってて間違ってます。すみません。
最終版は以下のとおりです。
これはPTCファイルから直接コピペしたので間違ってないはずです。

DTREAD(DATE$),Y,M,D:Y=Y-(M<3)M=M+(M<3)*12↓
H=(Y+(0OR Y/4)-(0OR Y/100)+(0OR Y/400)+FLOOR((13*M+8)/5)+D)%7?MID$("SUNMONTUEWEDTHUFRISAT",H*3,3)


ツェラーの公式

ツェラー(zeller)の公式とは、任意の日付の曜日を計算するための公式です。
パソコン黎明期から、カレンダープログラムなどでよく使われておりました。
自分も昔プログラムを作った時は、なぜそのような式になるのか、まったく理解しないまま使った覚えがあります。

今回は、ちゃんと理解してからソース書きましたので、覚書という意味と、基本的な導入のところでつまづく方向けに少し解説を書いておきます。


(1)基本的な考え方

ある基準日を定めて、この日を例えば日曜日とします。
この基準日からk日後の曜日はなんでしょうか。

h=k mod 7とします。「k mod 7」とは、「kの7による剰余」を表します。つまり、「整数kを7で割った時の余り」のことです。
このhが0の時はもとの曜日と同じであることを表します。

例えば、k=7だったら、7を7で割った余りは0なので、同じ日曜日であることがわかります。
つまり、7,14,21,28,...と7の倍数日後は全て日曜日になることがわかります。

また、余りが1から6であれば、日曜日の1から6日後なので、余りが1,2,3,4,5,6であれば、それぞれ月曜日、火曜日、水曜日、木曜日、金曜日、土曜日であることがわかります。

このように、基準日の曜日がわかっていて(条件1)、かつ曜日を求めたい日が基準日からk日後であることがわかれば(条件2)、求めたい日の曜日を求めることができます。

例えば2013年4月1日を基準日とします。この日は月曜日だった(条件1を満たす)。
2013年4月25日は何曜日でしょうか。
4月25日は4月1日の24日後です(条件2を満たす)。
24を7で割った余りは3です。
基準日とした4月1日は月曜日でした。その3日先の曜日だから、4月25日は木曜日です。カレンダーで確かめるとその通りであることがわかります。

では、5月1日は何曜日でしょうか。


(2)任意の年月日の曜日を求めるための基本的な考え方

5月1日は何曜日でしょうか。

5月1日は4月1日の一月先です。
4月は30日まであります。
ということは、5月1日は4月1日の30日後です。
k=30だから、30 mod 7は2です。
4月1日は月曜日だったからその2日先の曜日は水曜日です。

2014年4月1日は何曜日でしょうか。
これも同じ考え方で計算できます。
2014年4月1日は2013年4月1日の365日後です。
これでk=365 mod 7=1で、火曜日とわかりました。

では仮に1年1月1日の曜日がわかっているとします。
すると、任意の年月日y年m月d日の曜日は、1年1月1日からy年m月d日までの経過日数を7で割ればわかることになります。

原理的には、この方法で任意の日付の曜日を求めることができます。
しかし、実際には上記の経過日数を求めることは簡単にはすみません。

考慮しなければならないルールが2つあります。

ひとつ目のルールは、ひと月の日数が一定でないのでそれを考慮すること。
1〜12月のそれぞれの日数は、31,28(閏年は29),31,30,31,30,31,31,30,31,30,31です。

ふたつ目のルールは、閏年の考慮です。
閏年に関するルールとしての暦には、ユリウス暦グレゴリオ暦があるが、現在の日本ではグレゴリオ暦が採用されているので、以後はグレゴリオ暦についてのみ考えます。
グレゴリオ暦では、閏年は以下のルールで決まっています。
その年(yとしよう)が4で割りきれる時、閏年です。ただし、100で割りきれる時は閏年でない。ただし、400で割りきれる時は閏年となります。
このややこしいルールは、400年の間に97回の閏年を入れるためのもので、こうすることで400年間の平均の一年の日数を365.2425日にして、実際の地球の公転周期にできるだけ近づけようとする工夫なのです。

上記二つのややこしいルールを、うまいこと一つの式で表したのが、ツェラーの公式です。


(3)フェアフィールドの公式へ

さて、wikipediaの「ツェラーの公式」の項を見ると、フェアフィールドの公式(公式Ⅰ)から、公式Ⅱに変形し、さらに最終的なツェラーの公式(公式Ⅲ)に変形しています。

このフェアフィールドの公式(公式Ⅰ)とはどういうものでしょうか。

この式は、グレゴリオ暦が1年1月1日から施行されているとして、1年1月1日からの経過日数を計算し、経過日数の7の剰余を求めることで曜日を求める式となっています。
この一つの式の中に、複雑な月と閏年の計算を含んだものとなっています。
mod 7の部分を除くと、1年1月1日からの経過日数だけを知ることもできます。
例えば、2013年4月1日をこの式にあてはめると、734958日(後述の注意書き参照)であることがわかります。

実際にはグレゴリオ暦が施行されたのは1582年10月15日ですが、仮に1年1月1日から施行されていたとすると、1年1月1日は月曜日だとわかっています。
すると、734958の7の剰余を求めると0であるので、2013年4月1日は月曜日であることがわかります。

なお、少し補足の必要がありますが、上記のページの式で見ると、「y 年 m 月1日 〜 y 年 m 月 d 日」が「d (日)」となっています。
m月1日〜m月d日ならば本来は、 d-1日間なのだが、ここではd日間となっています。
これは式の間違いではなく、7の剰余をとった時の 0に相当する曜日を日曜日にあわせるため、式全体に1を足しているためです。
つまり、公式Ⅰからmod 7を除いた式、 365y+[y/4]-[y/100]+[y/400]+[306*(m+1)/10]+d-428 ([ ]はFLOOR関数を表す)で算出されるのは、1年1月1日も含んだ(いうなれば基準日1年1月0日からの)経過日数になっているので、厳密に1年1月1日からの経過日数としたい場合には式からさらに1を引いて、最後の項を-429とする必要があります。

さて、上記の式で実際に曜日はわかりますが、これは結構大きな数の計算をしなくてはならず、暗算などで曜日を知りたいときには不便です。
また、コンピュータで扱う場合でも、16ビットの整数演算を超えてしまうので、黎明期の8ビットパソコンで計算するにも不向きでした。

そこで、フェアフィールドの公式を、剰余計算の法則を使って変形し、暗算あるいは筆算で簡単に計算できるようにしたのがツェラーの公式です。
(ツェラーの公式が生まれたのは19世紀なので、もちろん、8ビットコンピュータのために作った公式ではありません。)

人が手計算をするには公式Ⅲが適しますが、コンピュータが計算するには16ビットの演算範囲さえ超えなければよいので、手順が簡単な公式Ⅱを用いることが多いです。
140曜日計算で使った式もこの公式Ⅱです。

もう少し補足が必要そうですが、かなり長文となったので、とりあえずここまで。

140コムソート

ソートアルゴリズムの一種である、コムソートをプチコンで実装してみました。
プチコンにはSORT命令およびRSORT命令があるので必要性は全くないのですが、アルゴリズムの勉強として実装したものです。

コムソートは1991年に開発された比較的新しいソートアルゴリズムです。
コムソートという名前の、コムは櫛(くし)のことです。これはソートする様子が櫛で梳くような動きとなるからだといわれています。
アルゴリズムの分類としては、最も原始的なソートアルゴリズムの一つである、バブルソートの改良版となります。
なので動作原理はバブルソートそのものです。
今回はSWAP命令を使うため、バブルソートの改良版であるコムソートを選んだわけです。
アルゴリズムについてはwikipediaの「コムソート」の項を参照してください。


140コムソート本体は、本当にソート部分しか実装していないので、本体の前側に配列の定義を、本体の後ろ側にソート後の配列の表示を行うコードを追加したのが以下です。
ツイートしたのは本体部分のコメントも外した部分となります。

140コムソートの使い方は、Nに配列の要素数を、A()にソート対象となる配列を定義しておき、140コムソートを呼び出すだけです。
処理後はA()はソートされた状態となっています。

'INITIALIZE ARRAY
CLEAR
N=9:DIM A(N)
FOR I=0TO N-1
A(I)=RND(10):?A(I);" ";
NEXT:?

'140COMBSORT
'A():Array  N:A Number Of Elements
@140COMBSORT
H=0OR N/1.3
FOR I=0TO 1FOR J=0TO N-H-1
IF A(J)>A(J+H)THEN SWAP A(J),A(J+H)I=0
NEXT:I=I*(H<2)H=0OR H/1.3+(H<2)NEXT

'DISPLAY ARRAY
FOR I=0TO N-1
?A(I);" ";
NEXT:?
END

デコーダの設計

仕事が忙しかったりで進捗が停滞していたプチZ80ですが、多少進捗しました。

レジスタ、メモリ等の定義についてはすでにしていたのですが、命令のデコード部分の実装ですごく紆余曲折がありました。

まず、以前に書いたとおり、1バイトのオペコードを3ビットごとに分けて読むとよい、という情報を読んだので、上位2ビットを命令の大分類として、その後の3ビットずつを読み取り、命令を体系化しようと試みていました。
が、結果からいうと失敗。

分岐した命令の中で例外のパターンについて調べてまた別命令に分岐するなど、訳がわからないプログラムができかけました。

理想的には、上位2ビットの大分類から枝分かれしたツリー構造になればよかったのですが、実際のZ80の命令体系は8ビットの中に命令群を詰め込むために、そんな単純な構造はとれなかったようです。


そんな時、 http://tomocyan.net/~kagurazaka/html/z80_cpu_00.html にある命令表を眺めていたら、やっぱり表にしちゃった方が単純だな、と思えてきました。
そこで完全に方向転換し、オペコードに対応するアセンブリコードを表で持ち、共通のアセンブリコードを一つのサブルーチンに分ける、ということにしました。

アセンブリコードの底本は、amazonnで見つけた「Z80アセンブラ入門」(東京電機大学出版局)とすることにしました。
この本の巻末付録にZ80命令セットがわかりやすくまとめられています。
この本を底本とすると、アセンブリコードは147種類にまとめられそうです。

例えば、オペコード 01、11、21、31は “LD dd,nn” という一つのアセンブリコードに帰着するので、これらのオペコードの対応表に“LD dd,nn”にあたるラベルを割り当てて、実行フェーズでそのラベルを呼び出します。

ということで、アセンブリコードのラベル表はLB_IS$()として定義します。
ついでに命令長とクロック数を、IS_LN()、 IS_CL()で定義しておきます。
1バイト目をフェッチし、CB、DD、ED、FDのいずれかでなければ、1命令で動作が確定するので、GOSUB LB_IS$(オペコード)でルーチンに処理を飛ばして、実際のオペコードの動作を実行します。

仮に1バイトで命令が確定しない場合には、命令長には0が入っているようにします。この場合、1バイト目のオペコードに応じて続く2バイト目の命令表が分岐するようにします。
命令が確定するまで、次の命令表を読みいくようにし、これを繰り返します。
ビット操作、ローテイト・シフトは4バイト目まで読まないと命令が確定しませんが、上記の仕組みでうまくいけそうです。


これで方針がはっきりし、また、見通しがかなりよくなりましたので、作業の分量もかなり事前に把握できるようになりました。
ただし、表がかなりのボリュームになるので、これを効率的にデバッグする方法が必要そうですが、それは後で考えることに。


残りの重要なものとしては、ペアレジスタとフラグがありますが、ペアレジスタについては次回に扱うことにします。


ここまで全く画面とか出てこなくてつまらないので、とりあえずHelloWorldしてみることにします。

そこで非常に簡単な仮想マシンを考えることにします。
プチコンGRPは256*192=49152=48Kbytesですので、&H0000〜&HBFFFまでのメモリ空間があります。
(あとでGRPを2枚つなげて64Kbytesをサポートするようにします。)
とりあえず、&H8000からの3072bytesを仮想マシンのテキストVRAMとして、ここにキャラコードを書き込むとプチコンの画面にテキストキャラとして表示するようにします。


後はHelloWorldを出すプログラムだけです。
アセンブリで作ったプログラムをハンドアセンブルして、BEDITで16進コードを入力しGRPファイルに書き込みました。

'' Z80アセンブリでHelloWorld
LD HL,&H8000 21 00 80
LD (HL),'H' 36 48
INC HL 34
LD (HL),'e' 36 65
INC HL 34
LD (HL),'l' 36 6C
INC HL 34
LD (HL),'l' 36 6C
INC HL 34
LD (HL),'o' 36 6F
INC HL 34
LD (HL),',' 36 2C
INC HL 34
LD (HL),'w' 36 77
INC HL 34
LD (HL),'o' 36 6F
INC HL 34
LD (HL),'r' 36 72
INC HL 34
LD (HL),'l' 36 6C
INC HL 34
LD (HL),'d' 36 64
INC HL 34
LD (HL),'!' 36 21
HALT 76

これでHello,world!と表示されました。

プチコンでムリヤリ再帰処理

昨日(2月1日)ツイッターでつぶやいた、プチコンでムリヤリ再帰処理について。
後でその時つぶやいた140フィボナッチを例に解説します。

プチコンはローカル変数がないので再帰処理できない、と言うのが一般的な話ですが、ローカル変数がどのように実現されているかを考えると、実はそれを自前でやれば再帰処理(らしきもの)は可能です。

Javascriptで書いた簡単な再帰処理の例です。階乗を求めています。

function factorial(x) {
  if (x==1) 
    return 1;
  else
    return x*factorial(x-1);
}
document.write(factorial(10));

factorialの最後で return x*factorial(x-1); とありますが、このxとfactorial(x-1)の呼び出し先でのxは別もののはずです。
仮に別ものでないとすると、このxは、factorial(x-1)の中で上書きされてしまい、xとfactorial(x-1)を掛け算(*)しようとした時におかしな値になってしまいます。

このようにfactorialは一度呼び出される毎に、その中で使うメモリは新たに確保されます。
10段の再帰がなされている時、一番深いところでは、factorial 10個分のメモリが確保されていることになります。


ではこれと同じようなことをプチコンでやるにはどうしたら、よいでしょうか。
もっとも簡単な方法は、スタックを使ってサブルーチン内で使う変数を保存することです。
といってもスタックの構造をプチコンが持っているわけではないので、配列で擬似的にスタック構造を実現します。

スタックを使って再帰らしきものを実現してみたのが140フィボナッチです。
フィボナッチ数を再帰処理を使って求めるものです。
(本当はハノイの塔をやりたかったのですが、140文字では無理でした。)

140フィボナッチそのままではスタックを使った再帰がわかりずらいので、それをわかりやすく書き直したのが次のコードです。

CLEAR:DIM S(99)      'S()はスタック
P=0                               'Pはスタックポインタ
N=15
GOSUB @2              'N=15の時のサブルーチン呼び出し
END

@2
'N, F, F1, F2 はローカル変数
'S(), P はグローバル変数

IF N<2 THEN F=1:RETURN

S(P)=N:P=P+1         '再帰呼び出し前に、ローカル変数Nの値をスタックに保存
                     'P=P+1でスタックポインタを進める
                     '※スタック保存するのはここまでに使った変数だけでよい
N=N-1:GOSUB @2:F1=F  '再帰呼び出し
P=P-1:N=S(P)         'スタックからローカル変数Nを取り出し
S(P)=N:P=P+1         'ローカル変数Nの値をスタックに保存
S(P)=F1:P=P+1        'ローカル変数F1の値をスタックに保存

N=N-2:GOSUB @2:F2=F  '再帰呼び出し
P=P-1:F1=S(P)        'スタックからローカル変数F1に値を取り出し
P=P-1:N=S(P)         'スタックからローカル変数Nに値を取り出し

F=F1+F2
?F
RETURN

140フィボナッチは上記のコードを140文字でどうにかおさめるように書き直したものです。

CLEAR:DIM S(99)N=15GOSUB@2:END↓
@2↓
IF N<2THEN F=1RETURN↓
S(P)=N:P=P+1N=N-1GOSUB@2:N=S(P-1)-2S(P)=F:P=P+1GOSUB@2:F=F+S(P-1)P=P-2N=S(P)?F:RETURN

プチZ80 開発その4(レジスタの設計3)

レジスタの設計3

ここまでに記述し忘れていたレジスタがあった。
汎用レジスタの裏レジスタだ。

汎用レジスタをR(0)〜R(7)としたので、裏レジスタはRX(0)〜RX(7)とする。
なおFレジスタについては表をRFと定義しているので、裏はRXFとする。

EX命令で表レジスタと裏レジスタの交換を行うことができるが、プチコンにおいてはSWAP命令で値のみ入れ替えるものとして、EX命令意外の操作対象としては、表レジスタであるR(0)〜R(7)、RFだけを扱うものとする。
(中身が入れ替わっているので、その入れ物であるレジスタは変わらないものとして扱う。実際のZ80の実装もそうなっているはず。)

一応、ほかにレジスタ関係で忘れ物はない、と思う。

プチZ80 開発その3(レジスタの設計2)

レジスタの設計2

汎用レジスタは前回配列に持つことに決めた。
ほかには以下のようなレジスタがある。
F フラグレジスタ 8ビット
I 割り込みベクタレジスタ 8ビット
R リフレッシュカウンタ 8ビット
IX、IY インデックスレジスタ 16ビット
PC プログラムカウンタ 16ビット
SP スタックポインタ 16ビット

これらは単純変数で持つことにする。

FレジスタはAレジスタと一緒に16ビットのAFレジスタとして扱われることがあるが、AFレジスタとして使える場面は限られていて、むしろFレジスタはフラグとしてしばしばビット操作の対象として扱われるので、単純変数としておく。

16ビットのカウンタについては、上位下位8ビットに分けて持つか、16ビット一本で持つかの選択になるが、16ビットへの加減算が多いはずなので、後者(16ビット一本)とする。

なので、変数名は以下とした。

変数名
'F : RF

'I : RI
'R : RR

'PC : PC
'SP : SP

'IX : IX
'IY : IY

プチZ80 開発その2 (レジスタの設計)

昨晩、pmanさんとツイッターで話したら、速度は実機の1/100もでなさそうなことがわかった。おそらく、Z80部分で1/100〜1/1000、実機エミュ部分はさらにそれ以上遅くなると思う。
もちろん、実用性は気にしないで速度は度外視なのでよいのだが、あらためて実機の速度で動かすのはむずかしそうだとわかった。
とりあえず、実機のエミュでなくすごく簡単な仮想的なマシンのIOを作れば?とアドバイスをもらったので、まずはそれを目指してみる。

実用性はないので、成果品にはそれほど意味はないのだが、ほとんどのエミュはZ80のエキスパートが作っていると思うので、Z80の初心者が勉強しながらその結果を残しておくと、後で資料としてはそれなりに役に立つのではないかと思う。

さすがにZ80は広く普及しているだけあって、まだ一冊も本を買っていないが、Webの情報だけでだいたいの内容を知ることができた。

現在参考にしているものは以下のとおり。

<参考資料>

Z80アセンブリャ講座 -入門編-
'http://www.systemax.jp/doc/Z80_text.html

Z80教室
http://njprog.com/z80_room.htm

Z-80仕様まとめ
http://d.hatena.ne.jp/Tnzk/20080318/1205820286

OPコード秘話
http://njprog.com/z80_002.htm

CPU Z80の設計 その1
http://www.ne.jp/asahi/yikai/class/schools/verilog/Z80_1.pdf

Z80命令説明書
http://www.alles.or.jp/~thisida/nd3setumeisyo/nd3_z80meirei.pdf

MSX2 TECHNICAL HANDBOOK
http://ngs.no.coocan.jp/doc/wiki.cgi/TechHan?page=FrontPage

Z80命令表
http://www.infonet.co.jp/ueyama/ip/software/z80_command.html



レジスタの設計

前述の「Z80教室」や「CPU Z80の設計 その1」によると、Z80のオペコードは3bitごとに読むと操作対象レジスタ等の意味が明確になるとのことだった。

例えば8ビット演算命令については、オペコードの2進表現が
(aabbbccc)
となっているとして、cccがレジスタを表す。
例えば、ADD A,B のオペコードは &H80 で、2進表現は(10000000)。
下位3ビットの(000)がレジスタBを表している。

これに基づくと、レジスタを配列にしておくと、オペコードと簡単に対応させることができる。

左がZ80レジスタ名、右がプチコンの変数名(配列)である。

'B : R(&B000) = R(0)
'C : R(&B001) = R(1)
'D : R(&B010) = R(2)
'E : R(&B011) = R(3)
'H : R(&B100) = R(4)
'L : R(&B101) = R(5)
'(HL): R(&B110) = R(6)
'A : R(&B111) = R(7)

ところでプチコンでは、単純変数と配列変数の間には、実行速度に2〜3倍程度の差があること思い出される。

一応設計としては、(1)速度を犠牲にして簡明さをとる、(2)速度をとって記述を冗長にする、の2つが考えられる。

Aレジスタであれば、変数名を「RA」とするなどだ。この場合、レジスタの数だけコード量が増えるが、多少の高速化は可能だ。

しかし、今回は(1)をとり、配列で持つことにする。
もちろん、最初の方針のとおり、まずは勉強が目的であるし、この方が最初の完成までは早いからだ。
どうしても速度を出したい欲が出てきた時には、コードを全面書き換えしなおしてもよい。
ということで方針も明確に決まった。

プチZ80 開発その1

何をとち狂ったか、急にプチコンZ80エミュレータを作ろうと思い立った。

前にも書いたけど、Tiny野郎さんがエミュレーション的なコードでP6の3Dゴルフシミュレーションをプチコン移植したとのことだったので、可能は可能なのだろうと思った。
それでZ80の解説記事を読み漁っているうちに面白くなってきてしまったので、本格的に製作にとりかかってしまった。

世の中にはZ80エミュレータのコードなどくさるほどあるので、効率からすれば使えそうなコードを移植するのが一番いい。
が、自分がやりたいのは、Z80、というかマイクロコンピュータの勉強なんである。
Z80のエミュを作る過程において、マイクロコンピュータの勉強をしたいだけなんである。
そのため、コードは完全にゼロから作ることとした。
なにしろ、Z80機械語は、パソピア7の時代にちょろちょろっと触っただけで、本格的に使ったことはない。それを今から勉強しようというのです。結構、大変なことが予想される。

上記のとおり、勉強が目的なので、実用的な面は求めない。
最終的には、簡単そうな特定の8ビットPCをエミュレーションしてみたいが、それが実用的なスピードで動くとはとても思えない。
大雑把に考えて、実機の10〜100倍程度遅いものになると考えられる。
それでも単に作ってみたいので作ってみることにする。

...

現状は、資料を読み漁りながら、メモリ、レジスタ、スタックなどを書いてみた。
今のところ、以前にBrainFuckインタプリタを書いたことが思いのほか役立っている感じ。BrainFuckは超簡単な仮想マシンだからね。

GRPをメモリとしてみなすんだけど、GRPの横幅がちょうど256なので、HLレジスタの上位下位がY座標X座標に分かれて簡単になるので、ちょっと感動(?)。

こんな感じ。

''MEMREAD_HL_8   8bit Read
''I: R(4)<=Address High 8-15bit, R(5)<=Address Low 0-7bit
''O: R(6)<=Read Data
@MEMREAD_HL_8
R(6)=GSPOIT(R(5),R(4))
RETURN

''MEMWRTIE_HL_8   8bit Write
''I: R(4)<=Address High 8-15bit, R(5)<=Address Low 0-7bit, R(6)<=Write Data
''O: Nothing
@MEMWRITE_HL_8
GPSET R(5),R(4),R(6)
RETURN

R(4),R(5)がH,Lレジスタ、R(6)が(HL)を表すことにした。
実際には、GRPは48KBしかないので、複数のGRPをまたがるように処理しないといけないんだけど、とりあえずは48KBのメモリしか載せてないと思って簡単に。


しかし、フラグレジスタの各ビットのフラグの扱いがよくわからない...。
もうちょっと調査が必要そうだな。

MML ソーサリアン「城」BGM

ひとつ前のエントリで「140文字プログラム集」をアップしましたが、ランチャーのBGMとしてソーサリアンの「城」のBGMをMMLで入力してあります。

一応、YouTubeにも音声を上げときましたのでよければご覧ください。

140プログラム集+α

あけましておめでとうございます。

新年企画として、今までほとんどQR化していない140文字プログラムをまとめたプログラム集をQR化しました。
そのままではさすがに使いづらいので、簡易ランチャーも付けました。(一部、ランチャーに戻らないプログラムや、エラーで止まる仕様のプログラムもあります。

また、実はこれがメインでもあるのですが、MMLソーサリアンの「城」BGMを収録しており、ランチャー画面で流れます。

ではQRをどうぞ。







◆収録作品

140スキー
140ゴルフ
140スロット
140タッチ
140ショット
140ジャンケン
140ペイント改
140ベーダー
140ランチャー(SEND編)
140ランチャー(RECV編)
140コンフィグ  (ソースのみ収録。ランチャーからは起動しません)
140スノー
140ピラミッド
140ザカリテ
140ザオリク
140UFO
140スター
140PAI
140コラッツ
140シュウォッチ
140テンカウント
140にじみフォント

MMLについて
ソーサリアンの「城〜ここで逢えるね〜」をMMLで収録しました。
当初は88版の再現を目指したのですが、あのFM音源のきらびやかな音色を再現するのはむずかしい、
ということで音色は標準音色を使いました。
そのうちリベンジするかも。