Last-modified: Mon, 03 Jan 2005 00:15:01 JST
[dynamic,cache:on]
powered by tds-1.6.2
まとめて記述。
人と会わずに、 本とコードに向かい合って休養中。
使い方を父母に教える。
不平等条約改正・日清戦争・三国干渉にかかる時期を外相として勤めた陸奥宗光。 その当人による自伝的外交録。
当事者の手になる書だが記述はきわめて客観的。 当時においていかに問題が生起し、 それに対して世論・外国政府がどう反応し、 己と自国政府が何を考え運動したかを丁寧に追っている。
後世、 事態が明瞭になってから当時を振り返って批判するのは簡単だが、 当事者にはそのような贅沢は許されない。 限られた情報・時間・資源の元で、 いかに決断を下すか。 最終的な目標も異なれば、 所持している情報も異なる外国政府・国内世論とどのように折り合いをつけるか。 不明瞭な視野の中、 取り返しのつかない決断を繰り返し迫られる。
明治期の日本外交を知ると同時に、 今日の政治を見る目を養うに有用な一冊。
鉄道関係者から薦められていたもの。 今読んでも古く感じないということは、 状況がまったく変わっていないということか。
あとは 年末に買ったマンガ を一通りと「Practical Statecharts in C/C++」をコード書きつつ読み進め中。
この数ヶ月、何度か質問された。 或いは父母に「なぜ PC の使い方が分かるの?」と聞かれ、 或いは知人に「なぜ CG を (それを仕事にできるぐらい) 知ってるの?」と聞かれ、 或いは仕事で「どうして、そんなアルゴリズム知ってるの?」と聞かれた。
一応の答えを出すのは簡単だけど、 他の人が再現可能な形で道を示すのは無理ではないかと思ってる。
たとえば CG について言えば、 最初は書籍 Real-Time Rendering 1st ed. か SIGRAPH の paper あたりを読んだのがきっかけで、 そこから関連書籍と paper を 10cm ぐらい読んで、 さらに研修と称して会社で遊んでいる最中に PS2 で簡単な 3D Engine を組んだり、 Maple でシミュレーションをして覚えた。
ただしこの背景として、 理論面では線形代数・複素解析・力学 *1・光学、 実装に当たってはアセンブラプログラミングや計算機論理設計の知識があったことが幸いしている。 私と背景が異なる人間には、 私の経験は参考にはなっても、 同じ結果を得るための確実な道標とはなりえない。
そんなわけで「なぜ○○できるの?」という質問には答えにくい。 正確を期すなら「それは私だから」となるのだろうけど、 そんな答えは質問した人の期待するところではない。
11:30 起床。生活ペースを戻すのに苦労しそうだ。
昨夜、ビデオに録画しておいた古畑任三郎を見る。
amazon で見つけたリスト。 ラフマニノフのピアノ協奏曲第二番は聞いてみたいな。
06:20 起床。 実家から直接出社して 10:00 会社着。
Hierarchical State Machine ( quantum-leaps.com 参照) の実装。 template 使って書き直しつつ、型の設計とデフォルト状態遷移の部分まで。
ミーティングと、新しく来る人の引越しのスケジュール確定。
プロジェクトに今日から加わって頂く方との顔合わせ。 今週中にもう一人加わる。だんだん大所帯になってきた。
メーリングリストの管理をメール経由で管理できるように ML サーバを設定。 手が足りなくなったら、 デザインや企画関係の ML 管理は、そちらのパート長にお任せする方向で。
スクリプトシステムの実装について打ち合わせ。
メインプログラマが 前に言っていた トリガ機能を実装したという事で、 コードを読みつつ仕様検証。 トリガ記述中からスクリプトスレッドの状態制御 (sleep, wakeup) を呼び出すとまずいことが判明したので、 いくつか実行時検査を追加してもらう。
スクリプトから呼び出す C++ 側の関数 (システム関数) を変更した場合に、 スクリプトの再コンパイル処理をどうするか相談。 コンパイル済みのスクリプトバイナリには「システム関数の番号」だけが残っていて、 シンボル名は残らない。 システム関数の番号がずれたり、システム関数のプロトタイプを変更した場合には
処理が必要になるが、 システム関数を 1 つ追加するたびにスクリプト全コンパイル&アーカイブ全作成は避けたい。 逆に、本来はスクリプトの再コンパイルが必要なのに、 それを忘れて実行時にエラーとなるのも避けたい。
スクリプト再コンパイル」は大して時間が掛からず *1、 「ファイルアーカイブ作成」がボトルネックとなりうるということで、 スクリプトは積極的に再コンパイルするが、 アーカイブ作成は保守的に行うように細工。
20:30
08:00 起床。09:30 出社。
Hierarchical State Machine ( quantum-leaps.com 参照) の実装続き。 ユニットテストを増やしつつ、シグナルのディスパッチ処理を実装。
ローカライズに関して、 作業工数を把握するために他プロジェクトにヒアリングを行う予定。 質問項目の洗い出しと決定。
多言語対応のフレームワーク決め。 スクリプタなどに提出してもらうファイルは UTF-8, 実機上での処理は UCS2 で統一する方向で。 サロゲートペアはしばらく忘れる。 これにともない、TrueType フォントファイルから
を作成するプログラムの作り直し。
そのあたりも含めて、プログラマの仕事割り振り微調整。 TrueType フォントファイルからグレイスケールのテクスチャデータを作るプログラムは、 Win32 で書いた方が楽だろう。
21:20
09:30 起床, 10:30 出社。
Hierarchical State Machine ( quantum-leaps.com 参照) の実装続き。
状態を表現するために関数ポインタを使っているが、 C/C++ では「その関数と同じ型の関数へのポインタを返す関数」を定義できないため、 次のいずれかの方法で回避する必要がある。
これまで前者で書いていたのだけど、かなり混乱を招くため後者に切り替え。 template を使って派生クラスの型を渡してやると、 キャストは this ポインタを派生クラスに static_cast する一カ所に集約できて、 すっきりする。
1 template <class T, class TSig>
2 class HsmState
3 {
4 public:
5 typedef struct HsmState (T::*StateHandler)(TSig const&);
6 HsmState(StateHandler handler) : m_handler(handler) {}
7 StateHandler get() const { return m_handler; }
8 private:
9 StateHandler m_handler;
10 };
11
12
13 struct HsmSignal;
14
15 class Hsm
16 {
17 public:
18 typedef HsmState<Hsm, HsmSignal> State;
19
20 State s1(HsmSignal const& sig) {}
21 State s2(HsmSignal const& sig) {}
22 };
23
24 int
25 main()
26 {
27 HsmState<Hsm, HsmSignal> state(&Hsm::s1);
28 }
実際には Hsm もクラステンプレートで、 HsmState には operator==() や boost に倣って unspecified_bool_type() などを追加してある。
ところで 5 行目の typedef にある struct, これを省略するとコンパイルエラーになる。 予期せぬ動作でちょっと驚き。
スクリプトのトリガ処理に関して最終的な仕様の詰めと、 利用するであろうプログラマを集めて、 議論&実装についての理解を深めるミーティング (立ち話)。
Perl 5.8 のインストールと UTF-8 対応具合の検証。 Perl 5.6 は捨てる方向で。
Ruby 1.8 は -Ku しておけば大丈夫か? 私は Ruby 使いではないので、使う人間に検証してもらおう。
プロジェクトにプログラマ一人追加。 予定通り、私のサブをやってもらうことに。 ネットワーク環境設定・ビルド環境の構築・現状のプログラムに関する簡単な説明など行って、 実際にコードをいじってもらう。
20:30
見積もりをお願いしていたのだけど、 $50 弱の品物を購入すると送料・手数料込みで $120 強になる。
……さすがに購入見送るか。
09:30 起床, 10:30 出社。
Hierarchical State Machine ( quantum-leaps.com 参照) の実装完了。 ユニットテストを書いて苛め中。
従来の State Machine (以下 Flat State Machine) と Hierarchical State Machine の違いは、 状態間に親子関係を定義できる事。 状態遷移機械は
この繰り返しで処理を進める。 Flat State Machine ではシグナルを処理するのは「現在状態」のみだが、 Hierarchical State Machine では「現在状態」が処理できない場合には自動的に「親状態」にシグナルが回される。
似た性質の状態を「親」としてくくり出す事で、 あたかも OOP の継承のごとく状態の差分プログラミングが可能になる。 このため各状態の記述は楽になるが、 逆に状態遷移処理がややこしくなる *1。
書籍 Practical Statecharts in C/C++ で紹介されている状態遷移関数は、
の組み合わせにより遷移を 7 通りに分類し、 それぞれに対して遷移処理を書いている。
組み込み機器を念頭に置き、 少しでも処理を軽くしようと固定長配列を使ったり、 自明とは言い難いポインタ演算を駆使しているのだけど、 私の用途ではそこまで性能がシビアではないため富豪的に解決。
自己遷移だけは特別扱いして、それ以外の場合。
実際には lca == src, lca == dst の場合もあるので、 境界条件に関して少し注意が必要だが、 コードにするとすっきりまとまる。
下のコードは記憶に頼って書いてるので、コンパイルできないかも。 意を汲んで下さい。
1 void
2 Hsm::trans(HsmState dst)
3 {
4 // メンバ変数 m_cur が現在状態
5 // メンバ変数 m_src が状態遷移を要求した状態
6 // 引数 dst が遷移先
7
8 // 現在状態から遷移を要求した状態まで上っていく。順次、退場動作を行う。
9 for (HsmState s = m_cur; s != m_src; s = getSuper(s))
10 exitAction(s);
11
12 if (m_src == dst) {
13 // 自己遷移
14 exitAction(m_src);
15 entryAction(dst);
16 } else {
17 // 遷移元状態からトップ状態までの経路と、遷移先状態からトップ状態までの経路を求める
18 std::vector<HsmState> src2top, dst2top;
19 for (HsmState s = m_src; s; s = getSuper(s))
20 src2top.push_back(s);
21 for (HsmState s = dst; s; s = getSuper(s))
22 dst2top.push_back(s);
23
24 std::vector<HsmState>::reverse_iterator i = src2top.rbegin();
25 std::vector<HsmState>::reverse_iterator j = dst2top.rbegin();
26 while (i != src2top.rend() && j != dst2top.rend() && *i == *j) {
27 ++i;
28 ++j;
29 }
30
31 // --i, --j が, m_src, dst と最も親等が近い共通の祖先
32
33 // m_src から lca まで上っていく。順次、退場動作を行う。
34 std::for_each(src2top.begin(), i.base(), boost::bind(&Hsm::exitAction, this, _1));
35 // lca から dst まで降りていく。順次、入場動作を行う。
36 std::for_each(j, dst2top.rend(), boost::bind(&Hsm::entryAction, this, _1));
37 }
38
39 // さらにデフォルト状態遷移を行う (以下略)
40 ...
41 }
i.base() で reverse_iterator を iterator に変換する際、 指している場所が1つずれるのが、 ちょうど良い感じ。
プログラマミーティング。 進捗報告など。
フォントテクスチャの作成・メッセージ表示部分などの担当者を変更したので、 その人に文字コードの基礎知識と、 現状のプログラミング言語対応状況などを口頭で 20 分ほどレクチャー。 それをふまえて、将来的に必要になるであろう資料について作成をお願いしておく。 伝達する相手が一人二人なら口頭の方が早いけど、 実作業する人間が増えると Web なり紙なりで資料を作っておかないと破綻する。
サブに来てもらったプログラマには、とりあえず Perl の勉強をお願いする。 何でも良いけど、文字列処理に強いスクリプト言語を1つ使えないと後で困るので。 それはそれとして、 現状のクラス図・シーケンス図と主要キャラクタのステートチャートも渡しておく。
あと Hierarchical State Machine についても理解してもらう必要があるけど、 これは私が簡単な資料をを用意した上で口頭で伝えるしかないか。 STL と Boost を多用しているソースコード読むのは慣れないと厳しかろうし、 Practical Statecharts in C/C++ は邦訳がないので、 原書を渡して読んでもらうのも辛かろう。
メモリ不足気味。 思ったより速いペースで .code, .data, .bss セクションの使用量が伸びてる。 問題となるコードを割り出して改修するなりメモリ配分を見直すなり、 近いうちに何らかの対処が必要だな。
あとソースコードのクロスリファレンス作成のため Global をプロジェクトディレクトリに入れ、 make 一発でクロスリファレンスの入った HTML ファイルを作るようにしておく。 人のコードを追う時に便利な事もあるので。
もっとも私は vim 使いなので、 普段は ctags でタグを作っており Global は使わない。 Windows のふつーのエディタでコードを書いてるプログラマ向け。
20:40
先日注文しておいたトュキディデスの「歴史」が到着。 睡眠時間を削ってしまいそうだ。
09:30 起床, 10:30 出社。
Hierarchical State Machine を苛め倒すも、音を上げず。 実装を忘れていた「現在状態は指定した状態の子か否か」を調べるメソッドを追加。 来週はステートモデルの継承について検証して、 それが終わったら Flat State Machine で書いてあるコードを順次 Hierarchical State Machine に移行かな。
プロジェクト新メンバーの作業環境構築。 プログラマの環境構築は比較的楽なのだけど、 それ以外は設定が Windows と UNIX 両方にまたがるので微妙に面倒。 今は、そのあたりを理解しているのが私とメインプログラマの二人だけだが、 今後の事を考えると二人とも忙しくなるに決まってるので、 別の人間に振りたい。 現在のプロセスを見直して簡略化した上で、 誰かに引き継ごう。
要は UNIX 使いが一人いれば良いのだけど、 どうやって UNIX 使いに仕立て上げたものやら。
その途中で、設定中の開発機で開発中のプログラムが動かないというトラブル発生。 いろいろ検証してみたけど、 これは問題の開発機が腐ってるんじゃないかなぁ……。 とりあえず、プロジェクト内で空いてる開発機を回して凌ぐ。
サブに来てもらったプログラマの Perl の勉強をちょっとお手伝い。 まだあわてる時期ではないので、マイペースでどーぞ。
デザイナとプログラマで、 他社のゲームの画面を眺めつつ、 エフェクト・シーン描画についてあれこれ。 実現方法は予想がつくけど、 それにしても実際に作れと言われたらかなり面倒そうなことも多い。 良く作り込んでる。
20:00