a23_useSelfMade #5
2023.02.09 Thu #1
- このプロジェクトに今必要な開発: たぶんKeyValueStore的な仕組み(簡単なやつでいいから)。それがあればインタプリタ実行とコンパイラ実行で変数を共有できるようになるから。
- このプロジェクトに今必要な作業: ここまでの成果をわかりやすくまとめるべき。1月10日から数えて1か月になるから、時期的にも悪くない。
- この二つを比較したら、たぶん成果まとめのほうが対外的には価値がある。自分が使うことだけを考えたら、まとめとかは意味ないけど。
- まあまとめたら何か気づくこともあるかもしれないから、自分が使うためだとしてもまとめるべきかも。
2023.02.09 Thu #2
- 「$」で始まるシェルコマンドを用意したのは本当に良かった。これがあれば「ああー、ファイルをリネームするコマンドが欲しい」とか思っても「$ren ...」でできてしまう。ディレクトリを作りたくなったら「$mkdir ...」でできてしまう。
- 当たり前だけどシェルにできることなら何でもできる。それだけのことが本当に助かる。
- これも当たり前だけど、このシェルコマンドが実現できたのはsystem()関数があったから。こういう、文字列を与えるとそれを解釈して実行してくれるっていう機能はeval的なものだけど、これが大きな可能性を持っていると私は思う。
2023.02.10 Fri #1
- 今は「変数を使わない範囲でプログラミングを楽しむ」のはPLAYしかないけど、これをもっと拡充させたら、小学生がプログラミングで挫折しにくくなるのではないかと思っています。
- それで、PCG(Programmable Character Generator)でドット絵をかいてタイル状に並べて絵を描くやつをやったらいいのではないかと思いつきました。思いつきましたが、昨日は頑張りすぎて疲れたのと、今日はいろいろと他にやらなければいけないこともあるので、今日は少しだけの開発にとどめることにします。
2023.02.10 Fri #2
- PLAYで演奏中はCtrl-Cが利かなくなることを発見。これはできるだけ早く直さなくては!
2023.02.11 Sat #1
- 一度は実装したけど結局は廃止した機能
- [1]行末のセミコロンを省略できる仕様にしていたけど(=言語処理系が改行の直前にセミコロンを自動で入れる)、for (...)とかif (...)の直後にセミコロンを勝手につけられると非常に困るので廃止に。でも今は{が必須なので、実は今は困らないのかもしれない。
- [2]かつてはeasy-Cのワンライナーモードは行頭にセミコロンがあるとREPLモードになって設定を記憶していたけど、結局はあまり役に立たなくて廃止になった。
2023.02.13 Mon #1
- 小学1年生(女児)にひきつづき、小学3年生(女児)もeasy-CでPLAY文を使った音楽演奏に興味を持ったので、やはりPLAY文の効果は絶大だなあと思っています。今まで何をやっても興味を持ってくれなかったので・・・(A~Zのキータイピングは興味を持ってくれていたけど)。
2023.02.13 Mon #2
- PCG命令をつけてみました。小学生が楽しむための機能です。
- mario.c[31行]
WINDOW 512,512;
PCG0 0,0,0x7799FF;
PCG0 5,4,4;
PCG1 "DD6622 FFBBAA 0x7799FF FFBB33";
PCG2 "A777777770A7777A BBBBBBBBBBBBBBBB CAAAAAAAAAAAAAAC"; // A,C,E
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 ADDDDDDDDDDDDDD0";
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 AD0DDDDDDDDDD0D0";
PCG2 "7AAAAAAAA07AAAA0 0000000000000000 ADDDDAAAAADDDDD0";
PCG2 "7AAAAAAAA070AAA0 AAA0AAAAAAA0AAAA ADDDAA000AADDDD0";
PCG2 "7AAAAAAAA0A0000A AAA0AAAAAAA0AAAA ADDDAA0DDAA0DDD0";
PCG2 "7AAAAAAAA0777770 AAA0AAAAAAA0AAAA ADDDAA0DDAA0DDD0";
PCG2 "7AAAAAAAA07AAAA0 0000000000000000 ADDDD00DAAA0DDD0";
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 ADDDDDDAA000DDD0";
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 ADDDDDDAA0DDDDD0";
PCG2 "00AAAAAA07AAAAA0 AAAAAAA0AAAAAAA0 ADDDDDDD00DDDDD0";
PCG2 "7700AAAA07AAAAA0 0000000000000000 ADDDDDDAADDDDDD0";
PCG2 "7A7700007AAAAAA0 AAA0AAAAAAA0AAAA ADDDDDDAA0DDDDD0";
PCG2 "7AAA77707AAAAAA0 AAA0AAAAAAA0AAAA AD0DDDDD00DDD0D0";
PCG2 "7AAAAAA07AAAAA00 AAA0AAAAAAA0AAAA ADDDDDDDDDDDDDD0";
PCG2 "A000000A7000000A 0000000000000000 0000000000000000";
PCG3 " ";
PCG3 " ";
PCG3 " CECEC ";
PCG3 " ";
PCG3 " ";
PCG3 " ";
PCG3 "AAAAAAAA";
PCG3 "AAAAAAAA";

- PCG命令を作ることと、このサンプルを作ることで、疲れ果ててしまいました・・・。
- インターネットでゲーム画面を検索して拡大して真似してみたのですが、たぶん細部は間違っています・・・。でもこれで、PCG命令でどんなことができるのか大体わかりますよね?
2023.02.14 Tue #1
- PCG2命令で複数キャラクタを同時に定義するとき:
// 今まで.
PCG2 "A777777770A7777A BBBBBBBBBBBBBBBB CAAAAAAAAAAAAAAC"; // A,C,E
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 ADDDDDDDDDDDDDD0";
PCG2 "7AAAAAAAA07AAAA0 AAAAAAA0AAAAAAA0 AD0DDDDDDDDDD0D0";
PCG2 "7AAAAAAAA07AAAA0 0000000000000000 ADDDDAAAAADDDDD0";
(後略)
// こっちのほうがいいんじゃないか?
PCG2 "A777777770A7777A" "BBBBBBBBBBBBBBBB" "CAAAAAAAAAAAAAAC"; // A,B,C
PCG2 "7AAAAAAAA07AAAA0" "AAAAAAA0AAAAAAA0" "ADDDDDDDDDDDDDD0";
PCG2 "7AAAAAAAA07AAAA0" "AAAAAAA0AAAAAAA0" "AD0DDDDDDDDDD0D0";
PCG2 "7AAAAAAAA07AAAA0" "0000000000000000" "ADDDDAAAAADDDDD0";
(後略)
- これを実現するには・・・手っ取り早いのは(これ重要!)lexerとtokenを改造すればよさそうです・・・。
2023.02.14 Tue #2
2023.02.15 Wed #1
- 小学1年生は今日もPLAY文を使って、演奏プログラムを書いていました。そのときに、「ああ間違えたー、演奏を止めたい!」って言っていたので、Ctrl-Cで止められるよと教えてあげたら、すごく喜ばれました(2月10日の書き込みのあと、しばらくして直したのです)。相当にうれしかったらしく、特に意味もなく何度もRUNしてはCtrl-Cして、そのたびにあはははと笑っていました。きっと待望の機能だったのでしょう。
2023.02.15 Wed #2
2023.02.16 Thu #1
- インベーダゲームができました。runでも!runでもどちらでも動きます(手元のバージョンのhl9.exeやacl1/なら)。
- invader.c[112行]
AInt fght[384] = {
0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,
0,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,0,
0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,
0,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,
0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
AInt invd[512] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,
0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,
0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,
0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
int inv[192], score, pnt, mwt0, fx, idir, wunit, ix, iy, invlin, lx = 0, ly, lwt, mwt, high = 0;
AWin *w = aOpenWin(324, 228, "invader");
for (i = 0; i < 384; i++) { fght[i] = fght[i] * 0x00ffff; }
for (i = 0; i < 512; i++) { invd[i] = invd[i] * 0x00ff00; }
restart:
score = 0; pnt = 1; mwt0 = 20; fx = 18;
nxtinv:
ix = 7; iy = 1; invlin = 5; ly = 0; lwt = 0; mwt = mwt0; idir = 1; wunit = 1024;
for (i = 0; i < 6; i++) {
for (j = 0; j < 26; j++) {
inv[i * 32 + j] = j % 5; }}
for(;;) {
// 表示.
aFillRect(w, 324, 228, 0, 0, 0x000000); aBitBlt(w, 24, 16, fx * 8 + 2, 13 * 16 + 2, fght);
aGrPrintf(w, 34, 2, 0xffffff, 0x000000, "SCORE:%06d HIGH:%06d", score, high);
for (i = 0; i < 6; i++) {
for (j = 0; j < 26; j++) {
if (inv[i * 32 + j] == 1) {
aBitBlt(w, 32, 16, (ix + j) * 8 + 2, (iy + i) * 16 + 2, invd); }}}
if (ly != 0) {
aFillRect(w, 2, 14, lx * 8 + 5, ly * 16 + 3, 0xffff00); }
// インベーダ全滅判定.
for (;;) {
for (i = 0; i < 26; i++) {
if (inv[invlin * 32 + i] != 0) goto skip0; }
invlin = invlin - 1;
if (invlin < 0) {
mwt0 = mwt0 - mwt0 / 3; aWait(1024); goto nxtinv; }}
skip0:
// wait処理.
aWait(wunit); wunit = 40; lwt = lwt - 1;
// キー入力.
for (j = 0;;) { // キーバッファが空になるまで繰り返す.
i = aInkey(w, 1);
if (i == AWinKey_Esc || AWin_isClose(w)) goto end;
if (i == 0) break;
j = aMoveDx(i);
if ((i == AWinKey_Up || i == 32) && lwt <= 0) {
lwt = 15; lx = fx + 1; ly = 13; }}
// 自機の移動.
fx = aSaturateInt(fx + j, 0, 37);
// レーザ移動.
if (ly > 0) {
ly = ly - 1;
if (ly == 0) {
pnt = aMaxInt(pnt - 10, 1); }}
// あたり判定.
j = lx - ix; k = ly - iy;
if (0 <= k && k <= 5 && 0 <= j && j <= 25) {
i = inv[k * 32 + j];
if (i > 0) {
ly = 0; j = j - i;
for (i = 0; i < 6; i++) {
inv[k * 32 + j + i] = 0; }
score = score + pnt; pnt++; high = aMaxInt(score, high); }}
// インベーダ移動.
if (mwt > 0) {
mwt = mwt - 1;
} else {
mwt = mwt0; ix = ix + idir;
if (0 <= ix && ix <= 14) continue;
if (iy + invlin == 12) {
aGrPrintf(w, 122, 98, 0xff0000, 0x000000, "GAME OVER");
for (;;) {
aWait(128); i = aInkey(w, 1);
if (i == AWinKey_Enter) goto restart;
if (i == AWinKey_Esc) goto end; }}
idir = - idir; iy++; ix = ix + idir; }}
end:
AWin_close(w);

2023.02.16 Thu #2
- [Q]easy-Cで作ったプログラムから実行ファイルを作りたいです。どうすればいいですか?その際には最適化オプションとかも細かく指定したいです。
- [A]な、なるほど・・・。それならまずは HL-9 の !run で実行してください。そうするとカレントディレクトリに副産物として ec_tmp.c というのができます。これはもはや普通のコンパイラでコンパイルできる状態になっていますので、好きなオプションをつけてコンパイルしてください。
- なお過去に1度でも!runしたことのあるものは、コンパイルキャッシュに入っていてそこから高速に実行されてしまいますので、 ec_tmp.c が生成されません。 cacheディレクトリの中を見て、該当する.cファイルを消してください。キャッシュがヒットしなくなるので、 ec_tmp.c が生成されるようになります。もしくは、ソースコードの末尾にスペースを一つ追加するなどして、ソースファイル内容がキャッシュと一致してない状態にしてもいいです。
こめんと欄