* a23_useSelfMade #2
-(by [[K]], 2023.01.18)
--親ページ: [[a23_useSelfMade]]

** 2023.01.18 Wed #1
-自作言語を作ってみてわかったのですが、C言語の { } を省略できるルールがかなり面倒です。たとえばforの中にifがあったとして、そのifの直後にelseが来るかどうかでforを閉じるタイミングが変わるので、処理が難しくなります(elseが来なければifの直後のセミコロンまでがforの範囲だけど、elseが来たらelseの終わりまで延長される。つまり先読みしないと閉じていいかどうか決められない)。・・・elseさえなければ簡単なのに・・・。
-でも一方で、 } のためだけに1行を使うのは行数が増えて悲しいです。だから私は今まで { } の省略を結構使ってきたのです(悲しいのは、できるだけ行数を減らしたいというこだわりと、行数が少なくなれば1画面あたりに表示できる情報量が増えるのに・・・、の2点による感想です)。

-私は悩みました。こんな記法がこの先何十年も使われたら、その都度言語屋さんは苦労し続けるのです。それは良くないです。こんなのは終わらせるべきです。実行しやすい形式こそ次世代に残すべきものです。・・・でもやっぱり行数は減らしたい・・・。

-ということで以下のような新スタイルを考えました。
--まあとにかく、基本的にはK&Rスタイル(でももはや原形をとどめてないかも)。
--でも { } は一切省略しない。
--でも } だけの行は行数がもったいないので、 } だけになったら前の行の末尾にくっつける。
--それだと繰り返し範囲がわかりにくいと思うかもしれないけど、インデントはそのままるので大丈夫(かな?)。Pythonだってインデントだけで繰り返し範囲を表現できているのだから、このスタイルもきっと慣れれば何とかなるはずだ!
--if~gotoや、if~breakや、if~continueやif~returnは例外で、{ } をつけなくてもよい(これでひとかたまりの命令だと思うから)。これらにはelseを付けてはいけない。
--1行は100文字以下。ifやforやwhileやdoは、文頭に置かなければいけない。
--ifやforなどのコードブロックが一行で書ききれないときは、中カッコ開きで改行する。
--中括弧閉じのあとは中括弧閉じか改行しか置かない。
-とりあえずこのスタイルに名前を付けておきます。KRKスタイルってことにします。

-ということで書き直した 3dwave.c[13行] です。
 AWin *w = aOpenWin(640, 480, "3dwave");
 int t, x, y, gx[42][42], gy[42][42];
 for (t = 0; AWin_isClose(w) == 0; t++) {
     aWait(8); aFillRect(w, 640, 480, 0, 0, 0x000000);
     for (y = -20; y <= 21; y++) {
         for (x = -20; x <= 21; x++) {
             float d = sqrt(x * x + y * y), z = sin(d - 0.1 * t) * 50 / (d + 5);
             int x0 = x + 19, y0 = y + 19, x1 = x + 20, y1 = y + 20;
             gx[y1][x1] = (x * 2 - y * 2 + z * 0) * 4 + 320;
             gy[y1][x1] = (x * 2 + y * 2 + z * 1) * 2 + 240;
             if (x0 >= 0 && y0 >= 0) {
                 aDrawLine(w, gx[y0][x0], gy[y0][x0], gx[y0][x1], gy[y0][x1], 0x00ffff);
                 aDrawLine(w, gx[y0][x0], gy[y0][x0], gx[y1][x0], gy[y1][x0], 0x00ffff); }}}}
http://k.osask.jp/files/pic20230117a.png
https://essen.osask.jp/files/pic20230117a.png
-実行すると分かりますが、波が動きます。

-この「実行しやすい形式こそ次世代に残すべき」というのは結構説得力があって(私には)、行ごとのセミコロンの省略も手元で実行する程度のものならいいけど、そうでなければちゃんとつけておくほうがいい気がしました。今はカッコのネストを見ながらセミコロンを付けるかどうか判定しているのですが、あまり良くないなあ、と。文字列リテラルが連続する場合を考慮できていないし・・・。
--ということで、これも修正。

~

** 2023.01.18 Wed #2
-とにかくどんどん使わないと自分のツールの良さも悪さも分からないので、過去作をeasy-Cに移植していくことにしました。

-kcubei.c[33行]
 static int sqr[24] = { 7,6,2,3, 6,4,0,2, 1,0,4,5, 7,3,1,5, 3,2,0,1, 7,5,4,6 };
 int vertx[8], verty[8], vertz[8], vx[8], vy[8], vz[8], sx[8], sy[8];
 int centerz[7], b0[160], b1[160], thx, thy, thz, xp, xa, yp, ya, zp, za, xt, yt, zt, t;
 AWin *w = aOpenWin(256, 160, "kcube-i"); int y0, y1, x, y, c, dx, *b, yk;
 for (i = 0; i < 8; i++) {
     vertx[i] = ( (i >> 2)      * 2 - 1) * 50;
     verty[i] = (((i >> 1) & 1) * 2 - 1) * 50;
     vertz[i] = (( i       & 1) * 2 - 1) * 50; }
 for (thx = thy = thz = 0; AWin_isClose(w) == 0; ) {
     thx = thx + 182; xp = aFf16Cos(thx); xa = aFf16Sin(thx);
     thy = thy + 273; yp = aFf16Cos(thy); ya = aFf16Sin(thy);
     thz = thz + 364; zp = aFf16Cos(thz); za = aFf16Sin(thz);
     for (i = 0; i < 8; i++) {
         zt = vertz[i] * xp + verty[i] * xa;  // x軸の周りに回す.
         yt = verty[i] * xp - vertz[i] * xa;
         xt = vertx[i] * yp + aMul64Shr(zt, ya, 16);  // y軸の周りに回す.
         vz[i] = aMul64Shr(zt, yp, 16) - vertx[i] * ya;
         vx[i] = aMul64Shr(xt, zp, 16) - aMul64Shr(yt, za, 16); // z軸の周りに回す.
         vy[i] = aMul64Shr(yt, zp, 16) + aMul64Shr(xt, za, 16);
         t = 9830400 / ((vz[i] + 26214400) >> 16);
         sx[i] = aMul64Shr(vx[i], t, 31) + 128; sy[i] = aMul64Shr(vy[i], t, 31) +  80; }
     for (l = 0; l < 6 * 4; l = l + 4) {
         centerz[l / 4] = vz[sqr[l]] + vz[sqr[l+1]] + vz[sqr[l+2]] + vz[sqr[l+3]] + 0x70000000; }
    aWait(50); aFillRect(w, 160, 160, 48, 0, 0x000000);
    for (centerz[6] = 0; (i = aArgMaxLstInt(centerz, 0, 7)) < 6; ) {
         y0 = 999; y1 = 0; c = AWin_col16(i + 1); centerz[i] = 0; i = i * 4;
         for (l = 0; l < 4; l++) {
             b = b0; j = sqr[i + l]; k = sqr[i + (l + 1) % 4]; AUpdateMinMax(y0, y1, sy[j]);
             if (sy[j] == sy[k]) continue;
             if (sy[j] > sy[k]) { b = b1; ASwapTmp(j, k, m); }
             yk = sy[k]; dx = (sx[k] - sx[j]) * 65536 / (yk - sy[j]); x = sx[j] * 65536 + 32768;
             for (y = sy[j]; y <= yk; y++) { b[y] = x >> 16; x = x + dx; }}
         for (y = y0; y <= y1; y++) { aFillRect(w, b1[y] - b0[y] + 1, 1, b0[y], y, c); }}}
http://k.osask.jp/files/pic20230118a.png
https://essen.osask.jp/files/pic20230118a.png
-実行すると分かりますが、立方体が回転します。今までこれを100行くらいで書いていた気がするので、すごい改善です。

~

** 2023.01.19 Thu #1
-昨日のkcubei.cは整数演算のみのバージョンですが、おおもとのオリジナル通り浮動小数点演算も自由に使ったらどうなるか知りたくて、書いてみました。
-10行減って、23行になりました。回転キューブが23行で書ける日が来るとは・・・。
-kcube.c[23行]
 static int sqr[24] = { 7,6,2,3, 6,4,0,2, 1,0,4,5, 7,3,1,5, 3,2,0,1, 7,5,4,6 };
 int sx[8], sy[8], b0[160], b1[160], y0, y1, x, y, c, dx, *b, yk;
 AWin *w = aOpenWin(256, 160, "kcube"); AVec3 vert[8], v[8], th; double centerz[7], t;
 for (i = 0; i < 8; i++) {
     vert[i] = AVec3_mul(100, AVec3_new((i >> 2) - 0.5, ((i >> 1) & 1) - 0.5, (i & 1) - 0.5)); }
 for (th = AVec3_new(0, 0, 0); AWin_isClose(w) == 0; ) {
     th = AVec3_add(th, AVec3_mul(3.14159265358979323 / 180, AVec3_new(1.0, 1.5, 2.0)));
     AMat33 mat = AMat33_mul(AMat33_rotZ(th.z), AMat33_mul(AMat33_rotY(th.y), AMat33_rotX(th.x)));
     for (i = 0; i < 8; i++) {
         v[i] = AMat33Vec3_mul(mat, vert[i]); t = 300.0 / (v[i].z + 400);
         sx[i] = v[i].x * t + 128; sy[i] = v[i].y * t + 80; }
     for (l = 0; l < 6 * 4; l += 4) {
         centerz[l / 4] = v[sqr[l]].z + v[sqr[l+1]].z + v[sqr[l+2]].z + v[sqr[l+3]].z + 1e6; }
     aWait(50); aFillRect(w, 160, 160, 48, 0, 0x000000);
     for (centerz[6] = 0; (i = aArgMaxLstDbl(centerz, 0, 7)) < 6; ) {
         y0 = 999; y1 = 0; c = AWin_col16(i + 1); centerz[i] = 0; i = i * 4;
         for (l = 0; l < 4; l++) {
             b = b0; j = sqr[i + l]; k = sqr[i + (l + 1) % 4]; AUpdateMinMax(y0, y1, sy[j]);
             if (sy[j] == sy[k]) continue;
             if (sy[j] > sy[k]) { b = b1; ASwapTmp(j, k, m); }
             yk = sy[k]; dx = (sx[k] - sx[j]) * 65536 / (yk - sy[j]); x = sx[j] * 65536 + 32768;
             for (y = sy[j]; y <= yk; y++) { b[y] = x >> 16; x += dx; }}
         for (y = y0; y <= y1; y++) { aFillRect(w, b1[y] - b0[y] + 1, 1, b0[y], y, c); }}}
http://k.osask.jp/files/pic20230119a.png
https://essen.osask.jp/files/pic20230119a.png
-なんとなくacl1のライブラリ関数について説明を書いておきます。
--AMat33_rotX: x軸まわりの3x3の回転行列を返します。
--aArgMaxLstDbl: double型の配列と、添え字の範囲[i0, i1)を渡すと、その範囲での最大値を探して、その時のiを返します。もし最大値が複数あるときは一番最後(Lst)に見つかったものを返します。
--AUpdateMinMax: min値、max値、監視対象の変数を指定すると、監視対象変数の内容に応じてminやmaxの変数を更新します。そういうマクロです。マクロなので、変数の型はintでもfloatでもdoubleでもポインタでもOKです。

-このプログラムの最大の見どころは、描画関数として aFillRect しか使ってないということです(矩形描画)。3D描画用の便利なライブラリを使ったとかじゃないのです。見ればわかりますが、行列とかベクトルの基本的な演算(和とか積とか)と上記のちょっとした便利関数を使っているだけです。それでも23行で回転キューブが書けるのです。

~

** 2023.01.19 Thu #2
-今度は簡単なレイトレーシングをやってみます。
-kray.c[56行]
 #include <acl1.c>
 
 AClass(Isect) { AVec3 hitPoint, nor, col; double distance; };
 AClass(Object) { AVec3 pos, col, nor; double rad; /* radius */ }; // Sphere(pos, col, rad) or Plane(pos, col, nor).
 AClass(Util) { AVec3 light; Object s1, s2, s3, p; };
 AInt32 col256(double t) { return (AInt32) (255.99999 * aSaturateDbl(t, 0.0, 1.0)); }
 
 void Sphere_intersect(Object s, AVec3 rayOrigin, AVec3 rayDir, AVec3 light, Isect *i) {
     AVec3 rs = AVec3_sub(rayOrigin, s.pos);
     double b = AVec3_dot(rs, rayDir), c = AVec3_dot(rs, rs) - s.rad * s.rad, d = b * b - c;
     if (d < 0.0) return;
     double t = - b - sqrt(d);
     if (t < 1.0e-4 || t > i->distance) return;
     i->hitPoint = AVec3_add(rayOrigin, AVec3_mul(t, rayDir)); i->distance = t;
     i->nor = AVec3_normalize(AVec3_sub(i->hitPoint, s.pos));
     i->col = AVec3_mul(aSaturateDbl(AVec3_dot(light, i->nor), 0.1, 1.0), s.col); }
 
 void Plane_intersect(Object p, AVec3 rayOrigin, AVec3 rayDir, AVec3 light, Isect *i) {
     double d = - AVec3_dot(p.pos, p.nor), v = AVec3_dot(rayDir, p.nor);
     if (v * v < 1.0e-30) return;
     double t = - (AVec3_dot(rayOrigin, p.nor) + d) / v;
     if (t < 1.0e-4 || t > i->distance) return;
     AVec3 hp = i->hitPoint = AVec3_add(rayOrigin, AVec3_mul(t, rayDir));
     i->distance = t; i->nor = p.nor;
     double d2 = aSaturateDbl(AVec3_dot(light, i->nor), 0.1, 1.0);
     if ((aReminder1(hp.x, 2) - 1) * (aReminder1(hp.z, 2) - 1) > 0) { d2 = d2 / 2; }
     i->col = AVec3_mul(d2 * (1.0 - aSaturateDbl(fabs(hp.z) * 0.04, 0.0, 1.0)), p.col); }
 
 void Util_intersect(Util u, AVec3 rayOrigin, AVec3 rayDir, Isect *i) {
     i->distance = 1.0e+30;
     Sphere_intersect(u.s1, rayOrigin, rayDir, u.light, i);
     Sphere_intersect(u.s2, rayOrigin, rayDir, u.light, i);
     Sphere_intersect(u.s3, rayOrigin, rayDir, u.light, i);
     Plane_intersect (u.p,  rayOrigin, rayDir, u.light, i); }
 
 void aMain(AComArg *aCA) {
     Util u; Isect i; AInt16 ix, iy, j;
     u.s1.rad = 0.5; u.s1.pos = AVec3_new( 0.0, -0.5, 0.0);       u.s1.col = AVec3_new(1, 0, 0);
     u.s2.rad = 1.0; u.s2.pos = AVec3_new( 2.0,  0.0, cos(6.66)); u.s2.col = AVec3_new(0, 1, 0);
     u.s3.rad = 1.5; u.s3.pos = AVec3_new(-2.0,  0.5, cos(3.33)); u.s3.col = AVec3_new(0, 0, 1);
     u.p.nor = AVec3_new(0, 1, 0); u.p.pos = AVec3_new(0, -1, 0); u.p. col = AVec3_new(1, 1, 1);
     AWin *win = aOpenWin(512, 384, "kray"); u.light = AVec3_new(0.577, 0.577, 0.577);
     for (iy = 0; iy < 384; iy++) {
         for (ix = 0; ix < 512; ix++) {
             AVec3 rayDir = AVec3_normalize(AVec3_new(ix / 256.0 - 1, (384 - iy) / 256.0 - 1, -1));
             Util_intersect(u, AVec3_new(0.0, 2.0, 6.0), rayDir, &i);
             AVec3 dstCol = AVec3_mul(rayDir.y, AVec3_new(1, 1, 1));
             if (i.distance < 1.0e+30) {
                 AVec3 tmpCol = dstCol = i.col;
                 for (j = 1; j < 4; j++) {
                     rayDir = AVec3_add(rayDir, AVec3_mul(-2.0 * AVec3_dot(rayDir, i.nor), i.nor));
                     Util_intersect(u, i.hitPoint, rayDir, &i);
                     if (i.distance >= 1.0e+30) break;
                     tmpCol = AVec3_new(tmpCol.x * i.col.x, tmpCol.y * i.col.y, tmpCol.z * i.col.z);
                     dstCol = AVec3_add(dstCol, tmpCol); }}
             aSetPix(win, ix, iy, aRgb8(col256(dstCol.x), col256(dstCol.y), col256(dstCol.z))); }}}
http://k.osask.jp/files/pic20230119b.png
https://essen.osask.jp/files/pic20230119b.png
-レイトレーシングが56行で書けるなんて、私は感激です!
-もちろんレイトレーシング用のライブラリ関数があるわけではなくて、描画関数は aSetPix のみです。自分で色を計算しています。

-[Q] やっていることは面白いとは思うんだけど、C++でやったらもっと短く書けるようになるんじゃないの?
--[A] そうですね、メンバ関数とか使えるし演算子のオーバーロードもできるのでもっと短くできそうです。でも今はみんながもう旬は過ぎたと思っているC言語でもがんばればここまでできたんだっていう、そうことをやりきりたいです。

~

** 2023.01.19 Thu #3
-世間では、大きなプログラムはかっこいいと思う人が一定数いるように思うのだけど、私はそうは思わない。私は大きなプログラムの達人ではなく、小さなプログラムの達人になりたい。
-大きなプログラムをうまく作れる人になりたければ、例えば一人ではできないので仲間を集めなければいけないし、役割分担もうまくできるようにならないといけない。でもそれはそれでいろいろトラブルの原因にもなる。・・・いや、たった一人で大規模なプログラミングができちゃうすごい人もいるけど、でもそれだって大規模に作るには小さく作る時とは違う高度な技術が必要になる。全体を理解する能力とか。
-私は小さいプログラムをうまく作ることを目指して本当に良かったと思う。小さいプログラムならすぐに全体は把握できるし、何回も作り直しても大した時間はかからない。それでどんどん完成度をあげられる。技術を極められる。他人と調整する必要もない。

~

** 2023.01.20 Fri #1
-昨日は忙しくて翌日分の開発ができなかったので、今日の更新はお休み(SecHack365のzoomミーティングが夜遅くまであった)。月曜日にはもちろん再開。

~

** 2023.01.22 Sun #1
-私は今はこうして言語を拡張しているというか、環境を整備してそれを徐々にupdateしているわけですが、でもそれを大規模にやりたいかというとそうではないです。Cコンパイラに1MBくらいのビッグな拡張をくっつけて「ほらどうだー、こんなに便利になったんだぞー」って言っても、「まあ確かに便利ですけどね・・・そりゃまあそこまでやれば当然でしょ」って自分にツッコミを入れてしまうのです。
-「小さいちょっとした改良でしかないのに、見違えるほど便利になる」みたいなのが私の目指しているところです。まあ「そんなことが可能なのか?」って真顔で聞かれたら、私も答えに困るのではありますが・・・。でももしうまくいったらすごいじゃないですか。私はすごくないことよりもすごいことをやりたいのです、どうせやるなら。

-kcubeには2つのバージョンがあります。整数演算のみのkcubei(33行)と、それ以外の命令も使うkcube(23行)です。普通に考えたら33行のバージョンはいりません。短くて簡潔なものがあるのだから冗長なものは不要なのです。・・・しかし、同じ実行結果が得られるのなら、言語に対して要求する機能が少ない33行バージョンは優れているとも思います。33行版はたぶんHL-9程度のシンプルな言語でも動かせます。でも23行版はそうではありません。
-高度な機能がある言語じゃないと動かせないプログラムは、私は価値が低いと思います。そんなプログラムをもらっても動かせない可能性が高いです。簡単な言語で動かせるプログラムは、多分言語を用意するのが簡単なので、動かせる可能性が高いです。
-いやもちろんC++でもPythonでも、今の主要なOSの上では問題なく使えるでしょう。でももしOSの自作したらどうでしょう。その自作OSの上で動くC++やPythonは誰が用意するのですか?自分自身です。それが大変すぎたら、結局どれほどC++やPythonで動くプログラムを持っていても動かせません。
-だからシンプルな言語でも動かせるプログラムは、(行数的に劣っていても、多少速度が遅くても)価値があるのです。

~

** 2023.01.23 Mon #1
-穴掘り法の迷路のプログラムのリメイクをしました。
-maze.c[14行]
 static int dx[4] = { 1, -1, 0, 0 }, dy[4] = { 0, 0, 1, -1 }, d[4];
 AWin *w = aOpenWinEx(47, 31, "maze"); aEchBox(w, 47, 31, 0, 0, 1, 2, 0); aEch(w, 1, 1, 0, 0, 0);
 for (i = 0; i < 1000000; i++) {
     AInt x = aRnd(23) * 2 + 1, y = aRnd(15) * 2 + 1, xx, yy;
     if (aGetEch(w, x, y) == 0) {
         for (;;) {
             for (j = 0; j < 4; j++) { // 四方の状態を調べる.
                 d[j] = 0; xx = x + dx[j]; yy = y + dy[j];
                 if (1 <= xx && xx <= 45 && 1 <= yy && yy <= 29) {
                     d[j] = aGetEch(w, xx, yy) * aGetEch(w, xx + dx[j], yy + dy[j]); }}
             j = aArgMaxRndInt(d, 0, 4);
             if (d[j] == 0) break;
             aEch(w, x + dx[j], y + dy[j], 0, 0, 0);
             x = x + dx[j] * 2; y = y + dy[j] * 2; aEch(w, x, y, 0, 0, 0); }}}
http://k.osask.jp/files/pic20230123a.png
https://essen.osask.jp/files/pic20230123a.png
-まあ簡単なプログラムなので、短く書けるのは当然かもしれません。

~

** 2023.01.23 Mon #2
-3dwavei.c[15行] : 整数演算のみでやってみました。配列も1次元にしてあります。
 AWin *w = aOpenWin(640, 480, "3dwave-i");
 int t, x, y, gx[42 * 42], gy[42 * 42];
 for (t = 0; AWin_isClose(w) == 0; t++) {
     aWait(8); aFillRect(w, 640, 480, 0, 0, 0x000000);
     for (y = -20; y <= 21; y++) {
         for (x = -20; x <= 21; x++) {
             int d = aFf16Sqrt((x * x + y * y) * 65536);
             int z = aFf16Sin(((d * 652) >> 12) - 1043 * t) * 50 / (d + 327680);
             int x0 = x + 19, y0 = y + 19, x1 = x + 20, y1 = y + 20;
             int y1x1 = y1 * 42 + x1, y0x0 = y0 * 42 + x0, y0x1 = y0 * 42 + x1, y1x0 = y1 * 42 + x0;
             gx[y1x1] = (x * 2 - y * 2 + z * 0) * 4 + 320;
             gy[y1x1] = (x * 2 + y * 2 + z * 1) * 2 + 240;
             if (x0 >= 0 && y0 >= 0) {
                 aDrawLine(w, gx[y0x0], gy[y0x0], gx[y0x1], gy[y0x1], 0x00ffff);
                 aDrawLine(w, gx[y0x0], gy[y0x0], gx[y1x0], gy[y1x0], 0x00ffff); }}}}
http://k.osask.jp/files/pic20230123b.png
https://essen.osask.jp/files/pic20230123b.png
-2023.01.18の写真と比べると、ウィンドウタイトルくらいしか違いがないかも?(笑)

~

** 2023.01.23 Mon #3
-MinGWの過去のバージョンはここから持ってこられるみたいです。古いバージョンが欲しくなったら、ここから探そうっと。
--https://sourceforge.net/projects/mingw/files/OldFiles/ 
-古いバージョンは、生成される.exeが小さくできる版もあるので、私にとっては重要です。

~

** 2023.01.23 Mon #4
-実は数日前から HL-9 の改造をしているのですが、 HL-9 で easy-C のプログラムが普通に動くようになってきました。これがうれしくてたまりません。楽しくなってきたので、HL-9のほうにも shell コマンドを付けてみたら、なんかもう使用感に差がなくなってきて、「言語自作は最高だ!」の気分になってきています(笑)。




//子供に教える手順
//mandelと迷路.
//カレンダー.

* こめんと欄
#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS