人が結構入れ替わる関係もあり、仕様変更などで他人のプログラムを修正することも多い。 私の作ったプログラムもかなり人の手が入っているのだが、文字列の終端文字'\0'を書いていた所がわざわざヌルポインタのマクロNULL に"修正"されているのを目撃してしまい、ピククと眉が痙攣。
NUL文字は「全てのビットが零である文字」である。一方、C言語ではヌルポインタを定数0で表す。 それでは、文字列の終端文字'\0'の代わりにNULLを書いた場合、どんな環境でも結果的に問題は起きないということになるのだろうか……。
そう、
char c; c = (void *)0;と書いた場合に c には結果的に'\0'に等しい値が入るのだろうか……ということだ。 定数0がポインタの現れるべき所にあった場合、それはヌルポインタとして解釈されるが、この式の右辺は「ポインタの現れるべき所」ではない、果たしてどうなのだろうか……と。 Cプログラマに「C FAQ」の内容を全て理解することを義務づければ済む話だが!
DMonkeyという。Delphi用のECMAScriptエンジンをC++Builder製の自作ソフトに組み込もうとした。 C++BuilderはDelphiのコードもコンパイルできるのだが、Delphiにあるユニット(Cで言うモジュールに当たるもの)が欠けているらしくリンクエラーになる。
Delphi で作成した関数を C++Builder で使用するには?に記述されているように、 DCC32.EXEを使ってDelphiのコードをC++のコードに変換できるので、Delphi6 Personal(このバージョンはフリー)から必要なコードを持ってくれば何とかなるかもしれない。 が、どうもうまくいかず、何となくライセンス的にもややこしそうなのでやめる。
着眼点を変えてDelphiでDLLを作成し、C++から使用することにした。 C++BuilderはDelphiのクラスライブラリを使用するために、__publishedというキーワードがあったり、Delphiの「array of const」型(?)に値を渡すための ARRAYOFCONST というマクロがあったりすることを初めて知った。 6年間C++Builderを使ってきて何たるていたらくよ。
さてDMonkeyには「拡張組込みオブジェクト」を追加する機能がある。 これはスクリプト上で自作のクラスを使用できるようにする機能で、DMonkeyを利用して自分のアプリケーションにマクロ機能を付けたい場合、必須の機能であろう。 しかしDMonkeyで定義されている型をC++Builderでコンパイルすることができないので、いかにDLL化しようともC++から直接使うことは多分不可能なのだ!
そこで「拡張組込みオブジェクト」はDelphiで記述し、C++のコードとの差異を吸収するコードを自分で書く……何だか迂遠だ。 C++で書かれた良いスクリプトエンジンが他にあればそれを使うのが一番いいのだが。 どちらにしろDelphiはフリーだし、まことに今更だがこの際使えるようになってみようと思う。
母が襲来。
文字通りたまの休みに、朝6時に起こされる。ひどすぎる。
「(高校の同級生の)○○君は大学院に行ってないのに○○で働いてるんだねーすごいねー」
……。
「結婚相手は見つからないのかね」
…………。
「そんなに忙しいんじゃ見つけようもなかろうがね」
ああそうなんだよ、きっとそうなんだよ。
すっかり忘れていたが、Cで書かれたスクリプトエンジンとしてはLuaがあるので、それを使えば良かったのだ。
ふと気がつけば7月の半ば、梅雨明け宣言か。5月の連休を潰されたのがつい昨日のことのよう……。 設計担当の人も、私に7月のスケジュールを指示する時に間違えて6月と書いていた。
スケジュールされていた作業が土曜で終わったため、日月が休みになった。 2週間ほど前に買ったDVD「トラトラトラ!」を見る。DVD版では渥美清の出演シーンがカットされていることを初めて知る。
以前見た時は配役がいいぐらいにしか思わなかったが、今回は細かい処まで史実に沿ったシーンが色々あることに気づいた。 鹿児島錦江湾で艦爆機が訓練している時、老人が「芸者にいいところを見せようとしている」と苦るシーンは、豊田穣の戦記小説でも描写されているので、なるほどこれかと合点がいった。
艦内で両手を上げる万歳をするシーンがあるが、日本海軍では艦内で万歳をする時は口で言うだけで手は上げないと 「海軍よもやま物語」に書いてあったのを思い出し、はて?と首をかしげた。 全くやらないというわけでもなかったのか。
"Lua C++Builder"でGoogle検索すると、C++BuilderでLuaを使用するサンプルを紹介している「RYOKO日記」というページがヒットする。 これを見れば簡単にLuaを自分のプログラムから使ってみることができるが、 Luaのテーブル(連想配列)の内容にどのようにアクセスするかについては載っていなかった。
C(C++)の側では、次のように書く。
int get_array( lua_State *L ) { int n = lua_gettop(L); /* 引数の数 */ if(n == 0){ return 0; } if (!lua_istable(L, 1)){ lua_error(L); return 0; } // int size = lua_getn(L, 1); for(int i=0;i<10;i++){ lua_pushnumber(L, i*i); lua_rawseti(L, 1, i); } lua_pushnumber(L,1); return 1; /* 戻り値の数 */ }Lua 4.0 では lua_getn() でテーブルの要素数を取得できたのではないかと思うが、Lua 5.0 にはこの関数が見あたらない。 廃止されたのか?
この関数を次のように登録したとして、
lua_register( L, "abc", get_array );Luaの側では次のように書く。実行すると、i=1, d=81 となる。
tbl = {0,3,5} i = abc(tbl) d = t[9]
私としては C の配列の中身を丸ごと Lua のテーブルにコピーするのではなく、ポインタ渡しか何かしたかったのだが、どうもそういう方法が見つからない。 フルユーザーデータとかライトユーザーデータというのは違うのだろうか。
Lua のグローバル変数を C から読み書きすればいいという考えもあろうが、 グローバル変数に値を入れて関数を呼び出すとか、関数を呼び出すとグローバル変数に値が入るなどというのはコボラーの発想であって、 変数はできるだけ局在させるべきなのである。関数はできるだけ引数で渡された値だけを使わなければならない。 そう、今私の超過勤務が多い原因のひとつは、コボラーの書いたプログラムの解読に時間がかかることなのだ……。
追記:"Lua 弾 制御"でヒットするページにもLuaの分かりやすい解説がある。 ※今日の日記で直接リンクを張っていないのは、リンクフリーかどうか分からなかっただけ。
誕生日のプレゼントは、いつもより1時間短い残業と、ニフティからのお祝いメール。 去年まで無視していたニフティからのお祝いメールがやけに眩しいぜ……。
最近、大学に戻った夢を見る。
「俺は何でこんな所に逃げてきているんだ!早く戻って出社しなければ!」
というパターンと、
「俺は実は卒業に必要な単位が足りなかったのだ!どうしよう働きながらじゃ履修するの無理!」
というパターンの2種類。やだねえ。
電源ユニットを確認する。 Channel Well TechnologyのCWT-300ATXだった。 電源ユニット・ケースの知識と実践で、
以前は、比較的廉価な筐体の組込み電源としては、CWT-300ATXはよく見かけました。TSUKUMOの廉価なアルミ筐体AL-888に搭載されていました。3.3+5Vは160Wです。Athlon 1.0GHzまでの推奨電源でした。と評されている。確かに電源込みケースで1万円ぐらいだった。
Athlon 64やGeForce FXを使うには全然足りないので、まず電源ユニットを交換しなければならない。
帰宅すると、宅配便の不在通知があった。 「定時に帰っても受け取れるかどうかぎりぎりの時間だな……」と考え、しばらくして今日は土曜日であったことに気づく。
やっと宅配便を受け取ることができた。 再配達を休日の午前中に指定すると落ち着かない。午前中ったって8時から12時まであるからな! おちおち寝ていられないわい。
時折「異国の丘」が口をついて出る。 と言っても「倒れちゃならない 祖国の土に 辿り着くまで その日まで」という歌詞だけがリフレインすることが多いが、私にとっての「祖国の土」ってなんじゃらほい。 シベリア抑留された人に失礼だという思いも生んで諸刃の剣。
世間では盆休みというものがあるらしく、そのせいかどうか久しぶりに土日が休みになった。 先輩社員が「ただの土日休みなのに何やら夏休みを貰えるような気分だぜ」と評し、 同意したくないが同意せざるを得ない。
午前2時から11時半まで寝る。食事して洗濯してクリーニング屋に行くと閉まっていて無駄足を踏んだ後、ちょっと本を読むと眠くなり、午後5時から6時半まで1時間半昼寝する。 疲れが抜けないよなあ〜全く……。
Borland C++はダウンロードの手続きが面倒なので、他のフリーコンパイラを試してみた。
Digital Mars C++で Lua をコンパイルしようとすると、コンパイルエラーになる。 どうもプリプロセッサが入れ子になったマクロをうまく展開できないようだ。 -eオプション(dmc -e)で、プリプロセッシングの結果を表示すると、 マクロの展開の順番が Lua のプログラマの意図と逆になっていることが分かる。それだけ。 LCC-Win32を使ってみると問題なくコンパイルできた。
LuaのテーブルにCからアクセスする方法をもう少し詳しく書く。 Cの側では以下のように書く。
/* 渡されたテーブルに値を追加する関数 */ int get_array( lua_State *L ) { int i; int n = lua_gettop(L); /* 引数の数 */ if(n == 0){ return 0; } if (!lua_istable(L, 1)){ return 0; } /* 数値をキーとしてテーブルに追加 */ for(i=0;i<10;i++){ lua_pushnumber(L, i*i); lua_rawseti(L, 1, i); } /* 文字列をキーとしてテーブルに追加 */ lua_pushstring(L, "ABC"); lua_pushnumber(L, 88); lua_settable(L, 1); /* 新しいテーブルを追加 */ lua_pushstring(L, "WXY"); lua_newtable(L); /* 新しいテーブルに要素を追加 */ lua_pushstring(L, "uho"); lua_pushnumber(L, 110); lua_settable(L, 3); /* 新しいテーブルを最初のテーブルの要素として追加 */ lua_settable(L, 1); return 0; /* 戻り値の数 */ } /* 数値を受け取ってprintfする関数 */ int print_num( lua_State *L ) { int i; int n = lua_gettop(L); /* 引数の数 */ if(n == 0){ return 0; } for (i = 1; i <= n; i++){ if (!lua_isnumber(L, i)){ printf("print_num : It's not number!\n"); return 0; } printf("%f ", lua_tonumber(L, i)); } printf("\n"); return 0; }
上記のget_array,print_num関数をlua_registerで登録し、Luaの側では以下のように書く。
local tbl={} get_array(tbl) for i = 0,9,1 do print_num(i, tbl[i]) end print_num(tbl['ABC']) local tbl2 = tbl['WXY'] print_num(tbl2['uho'])少し解説を加えると、tbl['ABC']=88、tbl2['uho']=110 になるわけである。
受け取ったテーブルを操作するのではなく、新しいテーブルを作成して返したいという場合もあるだろう。
int get_array2( lua_State *L ) { int i; int n = lua_gettop(L); /* 引数の数 */ /* 引数をスタックから削除 */ for(i=n;i>=1;i--){ lua_remove(L,i); } /* 新しいテーブルをスタックに積む */ lua_newtable(L); /* 文字列をキーとしてテーブルに追加 */ lua_pushstring(L, "muho"); lua_pushnumber(L, 999); lua_settable(L, 1); return 1; /* 結果の数 */ }スタックに引数が積まれたままだと、戻り値に差し支えるので 削除してから新しいテーブルを作成してスタックに積んでいる。
Luaの側では次のように書く。
tbl = get_array2()この時、tbl['muho']=999 となる。
Luaスクリプトの中断/再開を実現するlua_yield,lua_resumeについて。
Cの側では以下のように書く。
#include <stdio.h> #include <string.h> #include "lua.h" #include "lualib.h" #include "lauxlib.h" int print_num( lua_State *L ) { int i; int n = lua_gettop(L); /* 引数の数 */ if(n == 0){ return 0; } for (i = 1; i <= n; i++){ if (!lua_isnumber(L, i)){ printf("print_num : It's not number!\n"); return 0; } printf("%f ", lua_tonumber(L, i)); } printf("\n"); return 0; } int my_yield(lua_State* L) { printf("yield.\n"); return lua_yield(L,0); } int main(void) { int result; FILE *fp; char buf[4000]; lua_State* L = lua_open(); lua_register(L, "print_num", print_num); lua_register(L, "my_yield", my_yield); fp = fopen("a.lua","r"); if(!fp){ return -1; } fread(buf,1,sizeof buf,fp); fclose(fp); result = luaL_loadbuffer( L, buf, strlen(buf), NULL); if(result != 0) return result; printf("resume.\n"); lua_resume(L,0); printf("resume.\n"); lua_resume(L,0); printf("resume.\n"); lua_resume(L,0); printf("resume.\n"); lua_resume(L,0); return 0; }
Luaの側では次のように書く。
my_yield() print_num(1) my_yield() print_num(2) my_yield() print_num(3) my_yield()
実行してみると、resumeとyieldが交互に起きることが分かる。 Luaの側で最初にmy_yield()を書かないとうまく動かない。
結局これはどうもまだ分からない。 マニュアルを見ると、lua_newthread()とからめて説明されているが、こちらはなおさら分からない。 fork()のように分身ができるのではないのか。はてさて。
恒例の休日出勤。 この頃はアドレナリンが大量分泌されているのか、通勤路で小学生の頃の夏休みが脳内に広がり、 まるで明日からでも夏休みが始まるかのような楽しい気分に陥り、はっと我に帰ると不思議なものでちゃんと通勤路を辿っている。 小説などでふらふらと職場と逆方向の電車に乗るシーンがあるが、あれは意図しての行動ではなく実際無意識にそうなるのだろう。 居眠りして電車を乗り過ごすのと同じだ。
長い夏休みが欲しいね。果てしの無い長い夏休みが。 今職を辞したら何ヶ月食うことができるかと計算する毎日ですよ。 少なくともひと夏は余裕なわけよ、おっと一句浮かびましたよ。
夏過ぎて 秋来にけらし われ無職
あわれぼんくら 雇い手もなし
「われ無職」と「雇い手もなし」は意味がかぶっていかんね。 下の句は「今日も届くは ペラ紙一枚」の方がいいかな。 一応、今のところ冗談。
LuaはシフトJISに対応していない。 2バイト目が円記号('\'=0x5c)であるような文字(例えば"ソ")がスクリプト中にあると、 その部分が化けるか、コンパイルエラーになるかする。 「Lua SJIS」で検索すると、素晴らしいことに、これを回避してSJISのスクリプトをそのまま解釈できるようになるパッチを公開しているページが見つかる。
しかし、このパッチを適用し、lcc-win32 でコンパイルして実行してみると、 文字列 "ソ" を含むようなスクリプトは相変わらずコンパイルエラーになる。 すなわちSJISに対応しているように見えない。 もちろんプログラムの最初で #define _MBCS しているし、setlocale(LC_ALL, ""); もやっている。
なぜであろう。と、動作を調べてみると、lzio.c の zgetc() で isleadbyte() 関数 (引数の値が多バイト文字の最初のバイトなら真になる関数)が多バイト文字の判定に失敗し、 全て1バイト文字と判定していることが分かった。
そこで lzio.c の
if(isleadbyte(*z->p)) {を
if(isleadbyte((int)(unsigned char)*z->p)) {と書き換えると、SJIS対応として動くようになったので、 signed char と int のキャストの問題なのであろう(z->p の型は const char *)。 なお(int)の方は多分なくてもいいが、isleadbyte()の引数は int なので一応付けた。
コンパイラの問題なのか、CとC++ではキャストの動作が違うのか、 そもそも適用したパッチのバージョンが古いのか、私にはさっぱり分からない。それを調べる暇も無い。 はてさてパッチ作者に連絡したものかどうか。
良いフリーのマップエディタ「Platinum」がある事を知った。 リンクフリーかどうか確認できなかったので、例によって「Platinum マップエディタ」と検索キーワードを示すのみにとどめる。
で、検索してみると、かなり有名なようで、評価しているサイトが色々見つかる。 ゲームのマップの仕様を割り切ったシンプルなものにし、その上で高機能なツールを作った……というわけで、ゲーム作りに即座に役立つ一品と言える。
lcc-win32 + SDL でアクションゲームを作ろうという、泡沫のようなもくろみを実行に移した。 lcc-win32 はCコンパイラである。 スラッシュ2つのコメントを許すなど、色々拡張されているが、ANSI Cとしてコンパイルを行うオプションもある。
古き良き ANSI C でゲームを作るのがこんなにも心安らぐものだったとは……。 「ああ、これは private にしたいのに」といった欲求を覚えることがあるが、もどかしいこの思いもカ・イ・カ・ン♥(パピヨン)
「おもひでぽろぽろ」をレンタルで見る。 作品そのものよりも、ネットで検索して出てくる肯定評価と否定評価を読み比べるのが面白い。 この作品の評価が悪いということは、実は見終わった後、検索して初めて知ったのだった。
調べてみると、平成3年に作られた、昭和41年および昭和57年を舞台とする作品であるから、ターゲットとされた世代とは多分完全にずれているわけであり、あまり面白く感じないのは仕方あるまいて。 こう書くと「そういう問題か?」という感じもする。
大石まさるさんはもう「みずいろ」のような作品は描かないのだろうか。 「みずいろ」のように田舎暮らしをファンタジーで割り切ってしまった作品が読みたい。 もちろん「おもひでぽろぽろ」にそういうものを求めるのは筋違いではあろうが。
夏休み最後の日。LEE40倍カレーを食べながら「耳をすませば」をレンタルで見る。 何と良い作品だ。
調べてみると平成7年の作品。 10代の時に見たら精神的吐血して陰々滅々したエネルギーを溜め込む一因になったろう。 今はもはやそんなことは無いがな……(遠い目)
「おもひでぽろぽろ」にしろ「耳をすませば」にしろ、レビューを検索してみると 「実写でもやれるのになぜわざわざアニメでやるのか」という意見が見つかるのが気になった。 「おもひでぽろぽろ」を実写でやったら余計つまらないだろうし、「耳をすませば」を実写でやったらもはや別の作品ではないだろうか。
実写でやればいいと言う人はあまりアニメが好きでないか、アニメにはアニメでしかできないことを求めているか、あるいは他の理由があるのか…… そんなことを勝手に忖度しても意味ないな。うむ。
「耳をすませば」を見終わった直後は、良い作品であった……とにこやかに反芻していたのだが、 その後3日間ぐらいボディーブローのようにじわじわ効いた。 こんな劇薬的アニメを10代の時に見なくて良かったわい!ケッ!ケッ!ケーッ!
CからLuaの関数を呼び出すことを考えよう。 まず、Luaの側で次のように書く。print_array の引数に特に意味はない。
function f() print_array("ソ", 10, 'うむ。') end print_array(100)
C の側では次のように書く。
void print_lua_error(int result) { switch(result){ case LUA_ERRSYNTAX: printf("Lua statement error(%d)\n", result); break; case LUA_ERRMEM: printf("Lua memory error(%d)\n", result); break; default: printf("Lua runtime error(%d)\n", result); break; } } int print_array( lua_State *L ) { int i; int n = lua_gettop(L); /* 引数の数 */ if(n == 0){ return 0; } for (i = 1; i <= n; i++){ if (lua_isstring(L, i)){ printf("%s ", lua_tostring(L, i)); } else if (lua_isnumber(L, i)){ printf("%f ", lua_tonumber(L, i)); } } printf("\n"); return 0; } int main(void) { int result; FILE *fp; char buf[4000]; int size; lua_State* L = lua_open(); lua_register(L, "print_array", print_array); fp = fopen("a.lua","r"); if(!fp){ return -1; } size = fread(buf,1,(sizeof buf)-1 ,fp); buf[size] = '\0'; fclose(fp); result = luaL_loadbuffer(L, buf, strlen(buf), NULL); if(result != 0){ print_lua_error(result); return result; } printf("syntax OK. running start...\n"); /* 1回目の lua_pcall */ result = lua_pcall(L,0,0,0); if(result != 0){ print_lua_error(result); return result; } /* Luaの関数をスタックに積む */ lua_getglobal(L, "f"); /* 2回目の lua_pcall */ result = lua_pcall(L,0,0,0); if(result != 0){ print_lua_error(result); return result; } lua_close(L); return 0; }
1回目の lua_pcall() が無いと、Luaの関数 f は絶対に呼び出せない。 マニュアルの以下の部分を参照。愚かな私は見落としていて、はまった。
関数定義は実行可能な式であり、関数型の値を持つ。 Luaがチャンクをコンパイルすると、その中にある関数の本体もコンパイルされる。 そして、Luaが関数定義を実行したとき、関数は インスタンス化 (または クローズ) される。 この関数インスタンス (または クロージャ) は式の最終的な値である。
Luaの関数定義
function f() ... endは
f = function() ... endと同じであることを思い出すと分かりやすい。 つまり一回は実行しないと関数型の変数 f が定義されないわけだね。
劇薬系アニメを見た後、再び見たくなる心理というのは、激辛カレーを食べたくなるのに少し似ているか。 というわけで、今度は「海がきこえる」を、カリーHOTハバネロを食べながら見る。
主人公がヒロインを好きになる展開にいつなるんだろう……と思っていたら、 主人公の親友の「お前が武藤(ヒロイン)を好きだったのに気が付かなかった」という台詞。 私も気が付きませんでした。
そんなわけで、なにがなしリノアをいきなり好きになるスコールを彷彿とさせる作品だった。 むしろこれこそ10代のうちに見ないと面白くない作品なのかもしれない。
平砂食堂でまともな料理が出ている夢を見た。 夢であるから無論その風景を他人に伝えることはできないのだが、とにかく不気味な光景だった。
KAGOMEの「健康豆おかず ひよこ豆とうずら豆のチーズクリームソース」を食べる。 不味い。平砂オムレツに平砂カレーをかけて平砂ミートボールをトッピングしたよりなお不味い!! 平砂食堂の夢を見たおかげで感想も平砂風になった。
休日まみれの週だが、私にはいつもの通り休出まみれ。
ストリートファイターIII 3rd STRIKEが、7月にPS2で出ていたことを知り、買いに行く。 近所に2軒あるゲームショップのどちらにも新品は無く、中古で3,500円ぐらいであった。 amazonの新品価格は3,400円ぐらいなので迷ったが結局買わなかった。
もっともamazonで買うのは面倒くさいから、新品さえあれば定価の3,980円で買ったのだが。 7月発売じゃしょうがないことよ。
この日に何を書こうとしていたかの記憶は永遠に失われた。
今日はLuaのエラーメッセージをログファイルに出力する方法について。 この例ではファイルのオープン処理が手抜きである。
static void print_lua_log(char *fmt, ...) { va_list argp; const char *wmode = "a"; static int first = 1; FILE *fp; time_t t; char tm_str[32]; if(first){ wmode = "w"; first = 0; } fp = fopen("_lualog.txt", wmode); if(!fp) return; t = time(NULL); strftime(tm_str, sizeof(tm_str), "%y/%m/%d %H:%M:%S", localtime(&t)); fprintf(fp, "%s ", tm_str); va_start(argp, fmt); vfprintf(fp, fmt, argp); va_end(argp); fprintf(fp, "\n"); fclose(fp); } static int on_lua_alert(lua_State *L) { if(lua_isstring(L, -1)){ print_lua_log("%s", lua_tostring(L, -1)); } return 0; }
on_lua_alert 関数を、以下のように登録すれば、 コンパイルエラーなどのエラーメッセージがログファイルに出力されるようになる。
lua_register(L, "_ALERT", on_lua_alert);
「ラ・ピュセル 光の聖女伝説 2周目はじめました。」を買いに行く。 予想通り売り切れ。amazonで注文することにする。 果てしなくどうでもいいが、amazonでは2周目を二周目と表記している。正式名称と違う。
石井貞彦「闘魂ビルマ戦記」を読み終わる。 期間としてはインパール作戦の開始あたりから、終了後の退却までを描いている。 著者の部隊はそんなに補給に苦労したわけではない感じだが、やはり食事の話はやたらに多い。 非常に読みごたえのある戦記である。
児島襄「東京裁判」を読み終わる。 法廷の情景の他、被告の拘置所での処遇についても事細かに描写されている。 米軍人と同じ食事が与えられる一方で、自殺防止のために毛布を首より上にかけることを許されず、 高齢者のことであるから冬には肺炎になる者が続出した……など、初めて読む話が多い。
児島襄の作品は文章表現が上手く、面白いのでどんどん読みたいのだが、絶版になっている物が多いため古書店で入手するしかない。
明日も休出。今まで日記には書かなかったが、8月1日に秋葉にでかけて Athlon64 3200+、GeForce FX 5900XT という構成の新マシンを組んだのである。 というか以前のマシンの電源とマザーボードとCPUとグラフィックスカードとメモリとHDDを入れ替えたのである。
なぜ日付をはっきり覚えているかというと、多忙プロジェクトを7月末で脱出できるはずが9月までの延長ということになり、 ぶちきれてパッと散財することにしたからだ。 1日だけ休めた日曜日の午前中に秋葉に行って俺コンでパーツ一式を買い、午後に組み立てた。
GeForce FX 5900XTというのは割と3D性能が高い。少なくとも例えばFF11は高解像度モードで余裕のよっちゃんの筈だ。 まあFF11というのは3Dゲームとしてはかなり軽い方らしいが……。 しかしマシンを新しくしてから今まで遊んだ3Dゲームは、GeForce2世代でも動くパポタだけだ。 意味ねえ。
前のマシンの中身が余ったので、これで新しくPCを組んでLINUXマシンにし、 PHPとMySQLを入れるなどしたいと思っているのだが、これも時間がなくていまだできていない。 ああ……ラ・ピュセルでプリエを魔王にできるほどの暇が欲しいわ……。
年末帰省用の切符を購入するため、みどりの窓口に行く。 予想通りのぞみの指定席は喫煙席しか残っていなかったので、自由席にする。 空席状況はネットで調べられるので分かってはいたが。
UNIX USER1月号に、FreeBSD 5.3-RELEASEのDVD-ROMが付くということで書店に寄る。 しかし何故か無かった。というかFreeBSDはPC-98に入れてルータとして稼働させているのがあるからもういいか。 やっぱりLinuxにしよう。
ところでATXミドルタワーケースを買う必要があるが、店頭で買って持ち帰るというのは無理だろうか。 普通は送ってもらうものなのであろうか。 通販で買おうかねえ。ケースというのは場所を取るから、秋葉原では店頭には見本だけ置いているというパターンが多い。 その点つくばの店では普通にケースを店頭に在庫していたわけで、さすがつくばは土地がある。
2週間ぐらいずっと風邪気味だったが、本格的に熱が出たので会社を休む。
布団の中で前橋和弥「センス・オブ・プログラミング!」を読む。 氏の著作は他に「C言語 ポインタ完全制覇」しか読んだことがないのだが、これが大変面白かったので今度の新著も読むことにした次第である。
冒頭にて、
「プログラミングを始めたいのですが、どの言語がよいのでしょうか?」という問いに対し、次のように答えている。
どの言語から始めるかいつまでも悩んでいるぐらいなら、何でもいいからさっさと始めろこれはその通りだと思う。 この後、著者が最初に学んだ言語はBASICで、BASICが不便な言語であったが故に、後にもっと強力な言語の機能のメリットを知ることができた……と述べている。 私もBASIC(N88BASIC)から入った口なのでまことに同感できることしきりなのだ。
が、私はそれでも最初に選んではいけない言語というものがあるのではないかと考えている。COBOL74だ。
COBOL74をご存じでない方のために解説すると、文法的にはC言語に次の制約を課したものと思えばよい。
なぜCOBOL74に限定しているのかというと、COBOL85にはローカル変数があるらしいし、COBOL97はオブジェクト指向対応なんだそうである。 私は仕事ではCOBOL74で書かれたプログラムしか見たことがないが……。 まっ!ともかくプログラミングの最初の言語としてはCOBOLはお勧めできません!と結構強く主張しておきたい。
まだ思いっきり風邪なのだが、今週末に締め切りがある仕事を抱えており、間に合わなかった日にはまた週末出勤なので、二日も休めない。 寒い。長袖シャツと股引を買っておけば良かったわ……。
昨日の日記について、sugi氏に「それって要するにBASICなんじゃ?」と突っ込まれたので、 何故BASICは良くてCOBOLは駄目な印象を自分が抱いているのかを考えてみた。
で、昨日の日記の箇条書きに幾つか付け加えてみた。 最後の構造体についての制約(?)には「あれ?それじゃどうやって構造体のインスタンスを見分けるの?」と思った方もおられよう。 心配ご無用、COBOLでは型宣言、即、インスタンス定義なのでインスタンスはひとつしか作れません。
もっともそれでは同じレイアウトを持つデータ構造のインスタンスを複数使いたい時に困るので、COPY文というものがある。 まず次のような内容のファイルを作成する。これを原文と呼ぶ。
A01?:VARIABLE1 PIC X(5) A01?:VARIABLE2 PIC X(5)次に、プログラム中で以下のようにCOPY文を書く。
COPY 原文ファイル名 REPLACING ==A01?:== BY ==A01I-==. COPY 原文ファイル名 REPLACING ==A01?:== BY ==A01O-==.そうすると、プログラムでは以下の名前の変数が使用可能になる。
A01I-VARIABLE1 A01I-VARIABLE2 A01O-VARIABLE1 A01O-VARIABLE2このようにして変数の名前の一部を置換したソースを複写できるわけだ。
しかし、考えてみると、COBOLは古典BASICよりはずっと便利な文法を持った言語ではある。 では何が問題なのかというと、純粋に文法の問題というよりも、COBOLは仕事で扱うことが多いから、 COBOLに拘束されて他の言語を検討する余地が無い、というところか。 そんなわけでsugi氏の突っ込みは大変正しいものであった。
ふと思い立って、PCでDVDを再生した時と、PS2でDVDを再生(ただしIO-DATAのTVBOX2をS端子で介して表示)した時で どちらが良い画質になるか比べてみた。ソフトは「トラ・トラ・トラ」でディスプレイはCRT。 PS2で再生した時の方がややシャープで明るい画面になり、PCで再生した時は少しだけぼけた感じになった。 しかしPS2の方はMPEGのブロックノイズがはっきり出て気になる。
とりあえず「こっちで見たい!」と言うほどの差は出なかった。 まあ多分、綺麗に見たいならテレビにDVDプレイヤーを繋ぐのが一番なのだろう。
画像を半透明で描画するとか、フェードイン・フェードアウトする時の処理で、よくRGBの値を平均値を取るなどして単純に変化させているプログラムがあるが、 人間の目は緑の変化には敏感だが青の変化には鈍感、といった特性があり、RGB値を単純に線形で変化させるといささか不自然に感じられるはず……だ。
そのへんを真面目に考えたプログラム(RGBをYUVに変換して何かするのだったように思う)を紹介したサイトを前に見たことがあり、 探し回ったが見つからなかった。ブックマークしておけば良かったなあ。 こういうのは本があると便利なのだが、はてさてどんな本に解説されているであろう。
新宿で飲んだ。夕方4時半頃から始めたので店がすいていて良かった。
昔、プレステで、戦闘ロボットを設計し思考ルーチンを作って戦わせるゲーム「カルネージハート」があった。 今はそういうゲームを自分で作ることもできることに気が付いた。
プレイヤーはロボットの機体・エンジン・索敵システム・火器を選択し、思考ルーチンをluaで書く。 それを生産し、敵陣営と戦う。占領と補給ルールもあると良いかもしれない。
現在のパソコンならば開発も楽だろう。しかしもはや学生でない私には到底その暇が無い……悲しい。 もう既にないものだろうか。 思考ルーチンをプレイヤーが作るゲームはPC-98の昔からあるので、誰かが作っていてもよさそうなものだ。
帰省。妹がblogをやっていることを知る。 ちょっと見てみたが、身内の日記など読むものではないかもしれん。お互い心情的にちょっと気まずい。