カリ 画像処理を極める のシードベイントツールで領域内を塗りつ 用できる万能な方法はありません。処理方 g. 2 - ( b ) のような画素が近傍画素となりま ぶそうとして , 輪郭に微小な切れが存在し 法を工夫することによって , ある程度の改 す。 Fig. 2-(a) を 4 近傍 , Fig. 2-(b) を 8 近傍 善を図ることが可能ですが , 具体的な方法 と呼びます ( ただ単に近傍の画素数を付け たために塗りつぶしが画像全体に及んでし は対象領域の性質に合わせてそのつど工夫 まったという経験がある方は少なくないで ただけです ) 。 する必要があります。ここでは , 漏れ対策 リージョングローイングにおいて , 領域 しよう。ですから , シードベイントを用い として利用できる方法をいくつか紹介した の境界が Fig. 3 のようになっている場合は 4 る場合は , このような微小な切れを手作業 ですべてなくしたうえで行うことが一般的 いと思います。 近傍を採用したときと 8 近傍を採用したと 先ほども述べたとおり , 漏れ対策の完全 きで結果が異なります。 Fig. 3 で 4 近傍を採 です。 こで紹介す な方法はありません。また , 用した場合は , A の部分しか塗りつぶされ この現象はリージョングローイングにも 起こりえます。処理対象が写真などから得 る方法がすべてでもありません。もちろん ませんが , 8 近傍を使う場合は B の部分ま られた自然画像の場合 , ノイズや他領域と 場合によってはまったく別のアプローチが で処理が及びます。 実際のケースでは , 境界がこのような形 の接触などにより , 境界上に微小な切れ目 必要な場面もあるでしよう。ここては 「漏れ対策としてこのような方法もある」と になることはまれなので , どちらの近傍を ができてしまうことが多くあります。この いう考え方が理解できればよいかと思います。 使っても大差はありません。しかし , 一般 ような自然画像に対してリージョングロー リージョングローイング時の漏れを防ぐ 的には 4 近傍を用いているほうが , 処理が イングを適用する場合 , この問題はシード ペイント以上に深刻になる場合がありま ためのもっとも簡単な方法は , 塗りつぶし 広がりにくくなると考えられます。 す。なぜなら , 自然画像では , 境界部分が 条件のパラメータ設定を厳しくすることで 領域境界上の微小切れによる す。パラメータを厳しくすることで , 微小 そもそもあいまいな形なので , 手作業でカ 漏れの対策 な切れの部分がふさがって , 漏れを防ぐこ バーするにも限界があるからですまた , 手作業で行うことは最低限にし , ーきるだ とができる可能性が高まります。ただ , 前回取り上げたシードベイントアルゴリ の場合は本来塗りつぶしたい部分まで条件 ズムも含め , 画素を 1 つずつ調べて領域を け簡便に処理できるほうが , ユーザフレン ドリなため , できることならば始点の指定 外になってしまう可能性が生じ , 抽出の精 塗りつぶしていくタイプのアルゴリズムに 度が悪くなってしまう場合があるので , よ は共通の欠点があります。それは , 領域境 だけで処理が行えるようにするのがベスト い解決法とはいい難いでしよう。 だといえます。 界のどこかに , Fig. 4 のような微小な切れ そのほかのアプローチとしては , 微小な しかし , 結論からいうと , このような境 があると , そこから塗りつぶしが領域外に 界上の微小切れによるの漏れ対策として利 切れから塗りつぶし処理が漏れないような 広がってしまうことです。ペイントソフト 条件を新たに付け加えることです。ここで Fig. 4 領域境界上の微小な切れ はその 1 っとして , リージョングローイン グの際に複数の画素をまとめて処理する方 法を考えてみます。 この処理のイメージとしては , Fig. 5 に 示すような画素のまとまりを考え , そのま とまりを構成する画素のすべてが領域内の ときに領域拡張を行うものです。つまり , 1 回の処理単位を大きくすることにより , 微小な切れを領域拡張が通れないようにし てしまうのです。 具体的には , ある画素が領域内であるか を判別する際に , その近傍の画素も同時に 調べ , 近傍の画素すべてが条件を満たす場 合に , その画素を領域内とみなします。た とえ , 対象の画素が条件を満たしていても , 近傍の画素の中に 1 つでも条件を満たさな い画素があれば , 領域外とみなして塗りつ 000 : 000 ■「、を 00 ■■ 00 0 00000 0 000 0 、 00 一 00 境界上にわずかでも砌れ " が存在すると , そこから塗りつぶしが外部に漏れてしまう Fig. 5 領域境界上の微小な切れへの対処 00 コ 00 00000 00000 0 000 0 00 00 領域内外を判断するときに , 対象画素を 中心とするまとまりで考えるど微小な 切れ " からの漏れを防ぐことができる 画像処理を極めるアルゴリズムラボ 101
Fig. 3 1 や i に注目した複素平面 Fig. 4 クオータニオンの丿レール ( a ) 数式での表現 = 肥十黼十十 z (b)i, j, のルール = —ik=j 実はクオータニオンの初期ルールはこれ ください。 話が進むのだということを確認しておいて いただきます。ここでは , こんなルールで 面が足りないので , その説明は割愛させて てきます。これをきちんと理解するには誌 合が反転したりと何だか外積のにおいがし と残りの記号になったり , 逆に掛けると符 になっています。違う種類を掛け合わせる というのはいいとしても , それ以外は複雑 よう。同じものを掛け合わせると -1 になる す。まずは Fig. 4- (b) を見ていただきまし ちょっと理解しにくいルールになっていま さて , 気になる i , j , ですが , やはり ら四元なんですね。 ニオンは 4 要素構成というわけです。だか う 2 要素構成だったのに対して , クオータ 1 いので ここでれ j , によるルールを用 理解しやすい手順とはいえあまりにも汚 いてやればいいだけなのです ( Fig. 5- ( d ) ) 。 に複数の方法があるわけでもなく素直に開 乗算ならどうかというと , べクトルのよう ないですね。では , クオータニオン同士の な考え方ですね。あれ ? それほど難しく (Fig. 5- (c) ) 。これもべクトルと同じよう よう。まずはスカラー倍から始めてみます 気が楽になったところで乗算に進みまし で , 違和感はありません。 ごとに足したり引いたりするだけでよいの Fig. 5-(b) となります。各実数部分を要素 あるとき , それらを使って加減算すると Fig. 5- ( a ) のような 2 つのクオータニオンが じみの演算方法です。 すが , まさに先ほどいったべクトルでおな 演算方法として最初に行うのは加減算で 加減乗算 て進むことにしましよう。 が十分にあるので , それを最大限に生かし 幸い私たちにはべクトルに関しての知識 ります。 ろと演算方法や特性を考えていくことにな だけです。この初期ルールに従っていろい いて整理すると , Fig. 5- ( e ) のようにほん の少しきれいな形に整理できます。初めて クオータニオンらしい手順が登場しました。 それでもまだ覚えにくい形ですよね。 べクトルを用いた表記 そこで , 本物のべクトルを用いた表現を 行ってみましよう。れ j , それぞれに掛 かる係数を要素とした 3 次べクトルを用い て表記する方法です ( Fig. 6-(a))0 裸の実 数であったⅣを残してべクトルに畳み込ん だ感じです。このときのの部分をスカラ 一部 , の部分をベクトル部と呼ぶことも あります。これを用いると前述の加減算や 乗算は Fig. 6- ( b ) のように驚くほどすっき りと表現できます。 とくに乗算の場合 , やつばり出てきた内 積や外積がうまく利用されています・・・・・・と いいたいところですが , 事実はその逆です。 実数要素Ⅳが 0 の場合のクオータニオン「純 四元数 (pure quaternion) 」を考えて , その 乗算を行ってみてください。スカラー部は 内積 (scalar product) , べクトル部は外積 (v ector product) となります。実はこのクオ ータニオンという概念 , 私たちが勉強して きた 3D べクトル空間という概念よりも前 に成立していたのです。クオータニオンの 世界に現れる 3 次べクトルや内積外積を便 利だからという理由で拝借して 3D 表現に 利用したというのが本当のところのようで す。 こで注意しておくべき点として乗算の 交換法則が成り立たないということがあり ます。象と 2 は必ずしも一致しないと いうことです。外積が登場している時点で 予想できたことですが , 一応確認しておき ましよう。 逆クオータ二オン さっそく残りの除算・・・・・・といいたいとこ ろですが , 交換法則が成り立たないときた ら普通の除算はできそうにありません。行 列の除算を逆行列の乗算で行っていたよう Enter The 3D Programming 109
“オプジェクト指向”を こう考えてみよう Fig. 5 従来の方法とオブジェクト指向の方法 という人はいません。その「オプジェクト」 ( 現実世界のすべてのものがオプジェクト だという話はひとまず置いて , プログラム 上のオプジェクト ) とは , データ構造と振 る舞い ( 機能 ) が一緒になったものというこ とも一般に承認されるでしよう。オプジェ クトは , メッセージを受け取って振る舞い を実行し , 時にはほかのオプジェクトにメ ッセージを送ります。そのようにしてプロ グラムが動きます。 さてここで , オプジェクト指向以前の構 造化手法を見てみましよう。 C 言語で作成 されたプログラムを想定してください。構 造化手法では , 実現したい機能がまず先に あり , それをサプルーチンや関数に分割す ることによって実現していきます。機能の 実現に関しては上位の関数が責任を持って いて , 下位の関数を完全に制御することが 必要でした。 オプジェクト指向では実現したい機能が あっても , 自分で実行できません。なにし ろ機能はオプジェクトの中にまとめられて いるのですから。できることは , その機能 を担当するオプジェクトにメッセージを送 り , 信頼して任せるだけです。 さて , 「オプジェクト」なんていうあちら 側の存在を , ことによっては反対しそうな ものを「指向」するとはどういうことでしょ うか。「オプジェクト」をその原義から「自 分でないもの」ととらえて , 「オプジェクト 指向」を「自分でないものを主要なものとみ なす」と考えると , それはまさにオプジェ クト指向のプログラムで起こっていること を表しています。「自分でないものを主要 なものとみなす」は逆からいうと「自分を抑 える」ことになります。 プログラム内部のやりとりで , メッセー ジを受け取るオプジェクトは「客体」であり 「対象」です。しかし , メッセージを発する 「主体」は , 発するのみであとは何もやらず , 「客体」を主要なものとみなし , そちらに機 能の責任を任せます ( Fig. 5 ) 。「客体」であ るオプジェクトが「主体」となって , ほかの 主体 責任 主体 従来の方法 関数 ( サブルーチン ) 客体 呼び出し オプジェクト指向の方法 オブジェクト オプジェクトにメッセージを発することが あるかもしれませんが , そのときもやはり , 相手に機能を任せています。つまり , 「オ プジェクト指向」とは , プログラムで行い たい操作の実現において , ある主体がある 客体 : Object を主要なものとみなす , 「任せ る」ことです。オプジェクト指向とは任せ ることなのです。 そう考えると , オプジェクト指向の諸特 徴が見えてきます。任せるためにはそのオ プジェクトができることは何かを把握しな ければならないので , 「クラス」を使います。 「抽象化」によって , 受け取るメッセージの 特集プログラミング入門 " オブジェクト指向 " を考えてみよう 5 / 一覧 ( インタフェイス ) を公開します。また , 機能を任された以上は内部構造の公開は不 必要であり , 有害でもあるので「カプセル 化」してオプジェクトの内部を隠蔽します。 さらに , ある機能を任されたからには , 具 体的な動作はオプジェクトごとに異なって いてもよく , これが「ポリモーフィズム」と なり , それを実現する機構が「継承」です。 客体 責任 お任せ手法 もう一度「オプジェクト指向」という言葉 メッセージ
ぶしを行わないようにします。このように おりです。 ためには , 始点の座標を与える必要があり することで , 領域上の切れが微小であれば , まず , 基本的なリージョングローイング ますが , これはユーザが画像上でクリック そこから処理が漏れることがなくなりま のプログラムを List 1 に示します。処理の を行った点とします。 Pmacs プラグインで す。近傍だけでなく , さらに周辺の画素ま メインとなるのは , PMcDrawIt 関数です。 は , ユーザが指定した座標は関数 PMcSe で参照するようにすれば , さらに漏れが発 この関数に処理の始点となる座標を引き渡 tPoint で渡されるので , この関数が呼ばれ 生しにくくなります。 すと , リージョングローイングによる塗り た段階でリージョングローイングの処理を この方法は微小な切れの対策としては有 つぶし処理が行われます。処理の流れは , 行います。 効ですが , F . 6 のように領域内にもとも 前述したとおりです。この関数を利用する また , リ ージョングローイングを行う場 と狭い部分がある場合 , 塗り残しができて TabIe 1 主な PmacsAPI 関数 しまうという短所もあります。しかし , 領 機能 関数名 域が十分に大きく , 形状が単純な場合には 非常に有効な方法です。 リージョングローイングを利用して ROI を切り出す際に微小な切れによる漏れの対 策は , 抽出の精度を向上させるうえで重要 PMsSta 「 tPSet なものの 1 っといえます。これに対しては 今回紹介した方法のほかにも , 領域の形状 を考慮したパラメータを用いたり , 抽出状 況によってパラメータを変えるなどのさま ざまな方法が考えられます。いずれにせよ , どのような方法を採用するかについては 領域の性質に合わせて毎回設計する必要カ : あります。 引数 int n 取り出す座標の番号 ( 最初に登録し た座標を O としあとは連番 ) バッフアに格納した座標を取り出す POINT * pt 座標を格納するための領域 PMsGetEntryPoint PMsPSet に対する準備処理 EdtWin * edt 描画を行う画像が表示されている ウインドウ i nt x,y 画像上の 1 画素上にカレント色で描画 描画を行う座標 する i nt col カレント色 ID ( 通常は 0 ) O : 描画色 1 : 背景色 EdtWin * edt 描画を行う画像が表示されている 画像上にフラグをセットする ( フラグ ウインドウ 情報は Pmacs 本体で管理されている int x,y ため , プラグインは気にする必要はな 描画を行う座標 int flag フラグの値 ( 0 0 「 1) EdtWin * edt 取得する画像が表示されているウ インドウ int x,y 取得する座標 int kind プラグインの種類 ( 描画プラグイン の場合は PA 日 AM - D 日 AW を指定 プラグイン内で使用するバラメータ値 する ) を取得する int id パラメータの ID 番号 PMsPSet PMsSetD 「 awFIag プログラムの作成 それでは , 前述したアルゴリズムに従っ てプログラムを作成します。 今回は , 塗りつぶしとしてごく一般的な 処理と , 微小な切れに対する考慮を行った 処理の 2 種類のプログラムを Pmacs 描画プ ラグインとして実装します。今回使用した Pmacs プラグイン独自の関数は Table 1 のと Fig. 6 画素をまとめて塗りつぶす場合の問題点 画像上のマスク情報 ( フラグ含む ) を取 得する PMsGetMask PMsGetParamete 「 ■ 0 0 0000 0 0 0000 00 000 00 0000 00 0 000 0 0 0 ■ - ー・ 00 ー 000 Fig. 7 Pmacs プラグインのバラメータファイル 200 80 spin 10 10 0 255 Level spin 100 10 0 255 LeveI Fig 8 パラメータウインドウ Parameter Level Level 領域内に狭くなっている部分があると , そこで処理が止まってしまう場合がある 1 02 C MAGAZINE 2001 4
考えてみましよう。「ファイル」べースでも データベースでも , 「構造」自体はそれほど 大きな違いはありません。 Table1 のような 2 つのデータ構造を考えてみましよう。 ファイル指向のデータ管理の場合には , TabIe1 のデータ構造を入力するルーチンは たとえば List 1 のようになります。移植性 , データ互換性などの難しい問題はとりあえ ず無視して , こでは入力の手法自体を問 題にします。 ListI は典型的なファイル指向のデータ格 納方法で , 今でも現役で使われている方法 です。 CPU がデータを直接扱う内部形式で プロックにしてそれを 1 単位として扱いま す。この例では CPU が直接扱う内部形式で データを入力していますが , とくに内部形 式でなく , 一般的な " , " をセパレータにし , 改行を 1 単位としたテキストデータも「ファ イル指向」のデータ形式です。一般的には こういったデータの所持方法でも , ファイ ル内部のデータ検索を高速にするためにデ ータ先頭にファイル位置を格納したインデ ックスを持ったり , あらかじめデータ内の ある要素でソートしておいたりしますが , データ自体は 1 単位ごとに処理されるとい う特徴があります。データ形式に応じてプ ログラムの方法も , そのデータ形式に沿っ たものになります。 TabIe 1 のデータ構造を入力するルーチン List 特集プログラミング入門データベースの設計の基礎知識 61 TabIe 2 のような集計ファイルを考えてみ ましよう。ファイル指向のデータ構造をし たデータを扱う場合には , 次のようなアル ゴリズムを使うでしよう。 名簿について終わりまで繰り返し 国コードを取得 国別総収入から該当国 コードデータを取得 収入総額に名簿から収入を加算 国別総収入から該当国 コードテータを保存 終わり これは , たいていのプログラムの教科書 に掲載されている集計のアルゴリズムです。 この種のデータを扱うツール ( 工ンジン ) は コンピュータの大小に関係なく昔から存在 し , 今でも使われています。ツール ( 工ン ジン ) は「データを取得」「データを保存」と いう部分に非常に力を注いで設計されてお り洗練されたアルゴリズムでデータの入出 力を行い , こういった手法での不動の実績 を築いています。したがってほとんどのプ ログラマはこういったアルゴリズムをまず いちばん最初に学ぶことになります。また , 現代的なデータベースにおいてもこういっ た 1 単位でのデータアクセスの方法はちゃ んと提供されています。ただ , データベー スが提供しているこういったデータへのア #include く s セ d 土 0. h> #include <stdlib. h> / * データ互換性はクローズシステムなので考えない * / typedef 日セて uc セ—Meib0 { char 土 d [ 9 char 00 n い y ー code [ 4 char f 辷 st ーれ ame [ 32 char last—name[321; float gain; } MEm; / * 先頭から s 番目のデータをファイル土 npu セー f から読む * / ァータベスの設計 基礎知識 を構築するのが役目です。現代的なデータ ータベースを効率よく対話させるシステム プログラマは , SQL を通してユーザとデ この問い合わせを行う言語が SQL です。 に対して行い , その結果が答えになります。 という問い合わせ ( クエリ ) をデータベース 名簿 . COUNTRY-ID GROUP BY ー国 . COUNTRY—ID 0N 名簿 . co 駅 Y ー 1D I 駅 JOIN 国 FROM 名簿 SUM (GAIN) AS TOTM ・ GAIN (COUNTRY—NAME) , 名簿 . COUNTRY-ID, SELECT SQL, SQL Server 6.5 or SQL Server 7.0 ) , か ? 答えから先に書くと ( やや技巧的。 T- のような集計はどのように行うのでしよう では現代的なデータベースでは , 先ほど 問い合わせ言語 体がまずいと考えられます。 ム内に現れるようだとデータ構造の設計自 な繰り返しによる集計計算がもしプログラ タベースプログラミングです。上記のよう に必要なデータを提供するのが現代のデー ラマはその集計機能をうまく使ってユーザ 自体が高度な集計機能を持っていてプログ 慮されていません。データベースエンジン について高速に扱うようなことはあまり配 体として扱い , プログラマがデータ 1 つ 1 つ 現代的なデータベースではデータは集合 100 % 発揮できません。 かぎり , データベースエンジンはその力を 側が前時代的なデータアクセスをしている に提供される場合が主で , 逆にプログラマ クセス方法は従来のものとの互換性のため / * 土叩 u セー f はバイナリモードでオープンされている MEIBO * lnput (int po 町 FILE *input—f) MEIBO * て e し = 2. Ⅱ 00 (sizeof(MEIBO) fseek (input, size0f(MEIBO) * PO 町 SEEK—SET); fread ( て e し , 8 土 zeof ( IBO ) , 1 , input—f); return て e し一 / * メモリ確保 / * データ位置を計算 * / / * データ読み取り べースでは , データを直接扱うのはデータ を入力するときにほぼ限定されます。先ほ 思慮深く設計されたデ データをプログラム側で 自前で集計することはまずありえません。 ータベースでは , ども書いたように
五ロ め設定しておくことができます。 要素の設定数を調べることで配列数を知る よう。 ことができるからです。 int a = 1234 初期化 土北 a [ ] = { 1 , 2 , 3 , 4 , 5 島 float 123.4 float b ロ = { 1.1 , 2.2 , 3.3 , 4.4 , 5.5 孱 char c= 'C ' 変数にはその宣言時に初期値をあらかじ 配列を初期化するには , その配列の宣言 文字型の配列を初期化するには先ほどの 時に目を使用して , ( カンマ ) でそれぞれの め設定することができます。これを変数の 数値の場合と同じ設定の方法と , 配列の説 初期化といいます。初期化を行わなかった 値を区切って設定します。例の場合 , int 型 明時に使用した方法の 2 通りの設定方法が 場合 , その変数の種類によって自動的に 0 の配列 a の要素にはそれぞれ , a [ 0 ] には 1 , あります。下記の例の場合 , a, b, c のす が設定されるものと , ごみ値 ( 意味のない a [ 1 ] には 2 , a [ 2 ] には 3 , a [ 3 ] には 4 , a[4] べてに同じ内容が設定されることになりま 値 ) が設定されるものがあります。これら には 5 が格納されたことになります。 す。変数 a には文字コードを直接設定する によってプログラムが誤動作することも考 int a [ 5 ] = { 1 , 2 , 3 , 4 , 5 ことで , 変数 b には個々の文字 + \ 0 をばらば えられるため , 正しく初期化を行うことが oa セ b [ 5 ] = { 1.1 , 2.2 , 3.3 , 4.4 , 5.5 孱 らに設定することで , 変数 c には文字列を 大切です。 また , 次のように宣言文で添え字を省略 まとめて設定することで , 「 ABCD 」という 通常の変数を初期化するには , その変数 して , a [ ] = のように初期化しても上記の例 文字列を初期値として配列に設定していま の宣言時にそれぞれの変数へ値の代入文を と同じことと解釈され , 同じように初期化 す。 書きます。このことにより , 値をあらかじ することができます。コンパイラが初期値 char a [ 5 ] = { 65 , 66 , 67 , 68 , 0 島 文字 文字 10 進数 1 04 1 05 1 06 1 07 1 08 109 1 1 0 1 14 1 18 1 19 120 122 123 124 125 126 127 8 進数 120 122 123 124 125 126 127 130 131 132 133 134 135 136 137 140 141 142 143 144 145 146 147 数 佳 ~ 0 1 ワ」っ 0 4 L-O ( 0 「 / 8 0 1 ・つムっ 4 一 0 ( 0 「 / 8 8 8 8 8 8 8 8 8 8 8 C) C) C) C) C) C) 0 ) 0 ) 8 進数 1 50 1 52 1 53 1 54 1 55 1 56 1 57 160 161 162 1 63 1 64 1 65 1 66 1 67 1 70 1 72 1 73 1 74 1 75 1 76 1 77 100 101 102 103 特集プログラミング入門 c 言語入門講座 3 /
/ * 重なっている * / という式で得られます。 ( & 1 ) というのが当 たり判定で使われる範囲となります。キャ ラクタの大きさによってこの部分を変える ようにします。 ほかにもいろいろなプログラミングの方 法があります。専用の 2 次元配列を用いた り , 重なり具合を矩形ではなく円などとし WonderWitch でのデバッグは , 何かとめん どうなところがあります。ソースコードレベ ルのテパッグはできませんし , WonderWitch へいったんプログラムを転送したうえでプロ グラムを実行させるというわずわらしい手順 が必要になります。また , 致命的なミスがあ ると表示などがすぐにうまくいかなくなり , テパッグ作業がスムーズに行えません。 セオリーだとは思いますが , デバッグに関 する筆者の私見は , 「バグがあるかどうか検 証して動作を確認した部分を積み重ねていき , 問題があればその一歩手前の状態に戻す」と いうことを繰り返しているだけというもので す。「何々をしている処理」 , 「何々から受け取 る処理」というように部分ごとに分けてプロ グラミングをしている場合 , その部分でバグ がないことがわかっているなら , ほかの部分 に問題が必ずあるとすぐにわかります。この ようにバグがない部分を増やしていきながら , バグがあると思われる範囲を狭めていくよう にプログラミングを行います。 これを Wonde 「 Witch で実践するには , 筆者 の場合 , その方法の 1 っとして , ・始めに仕組みやアルゴリズムを実装する ・そのあとで Wonde 襯 itch 特有の処理を加 ・ WonderWitch 特有の処理は , それぞれの 処理が自分で使いたい形にできるかどう かテスト用ソースコードを作る というようにしています。 て計算で確認する方法などがよく使われて います ただ , この方法のままでは現在表示され ているキャラクタすべてに対して調べなけ ればいけません。そのため配列やハッシュ などを利用してできるだけ計算量を減らす 方法が使われています。 今回の当たり判定については , X 軸方向 にキャラクタがいるかどうかを示すバッフ アを作り , まずここでいったん調べてから 前述の式で当たったかどうかを判定するよ デバッグ方法 もっともバグが入りやすいのは , 自分で作 ったアルゴリズムや関数の連係など「ゲーム そのものに関係する処理や仕組み」です。シ ューティングゲームでは , 敵の動きを実現す るところや進行管理などがこれにあたります。 アドベンチャーゲームではシナリオテータを 解釈する部分などです。こうしたところは , Wonde 「 Witch で実際の画面表示などを行わな くてもテストできる場合がほとんどのはずで す。 それなら WonderWitch の処理を使わないよ うにしていったんソースコードをまとめ , そ れらをテストしてから WonderWitch の機能を 使うという流れでプログラミングするように してみましよう。こうして WonderWitch の機 能を使っていないソースコードにしておくし 通常の統合開発環境を使ったソースコードレ ベルでのデバッグ作業が行えます。 筆者は Borland C + + Builder 5 を愛用してい るので , こうしたアルゴリズムや処理の流れ をまとめたら , Borland C + + Builder 5 上でソ ースコードのトレースなどのデバッグ作業を 行い , ある程度処理の流れを完成させていま す。そのあとで表示など WonderWitch で提供 される機能を加えるようにしています。変数 値なども別ウインドウで確認することができ , ソースコードを 1 行ずつ解釈して実行するス テップ / トレース実行の機能によってプログラ ムの処理の流れが直感的に追いやすくなるの で , 非常に気分よくデバッグできます。 コラム 2 うにしています。この当たり判定は「キャ ラクタが移動したとき」に行うようにしま す。 ■当たり判定の注意点 スプライトとして設定したときに周囲が 空いているキャラクタ同士がぶつかった場 合 , その状態によっては「ぶつかったよう には見えない」場合が出てきます。このと きはそのぶんも含めて当たり判定を考えな ければいけません。 もちろん , ほかの開発環境でもかまいませ ん。フリーのテパッガとしてはたとえばボ ーランド ( 株 ) が無償配布している TurboDebu gger などがあります。このようにしてある程 度仕組みなどを完成させてからプログラミン グを進めるとよいでしよう。 Wonde 「 W 瓰 h の各機能は魅力的ですが , そ れが自分の思ったとおりの処理をしてくれる かどうかはわかりません。実際にそれらをテ ストする簡単なプログラムを作って試すこと が必要になるはずです。このとき , ただ単に テストをするだけではもったいないものです。 作っている本当のプログラムにその機能を組 み込むことを考えて , 呼び出す順番や関数な どを整えておくようにします。そうしておく し前述の仕組みを作ったソースコードとこ のテストプログラムから取り出した関数など を組み合わせることが簡単にでき , それによ ってバグがそれほど含まれないソースコード を作り出すことができます。 とはいえ , ある程度完成したプログラムを WonderWitch 上で微調整するときは , 昔なが らの変数など直接表示して行う p ⅱ ntf デバッグ (sprintf + text_put_string デバッグ ? ) をしてい ます。このとき表示が乱れることがあるので , 画面上の特定の部分はデバッグ用として使う ように分けることをしています。 このようにいろいろと気をつかっていけば スムーズなデバッグ作業は可能になるもので す。がんばってみてください。 1 3 イ C MAGAZINE 2 1 4
サポートしていないほうが普通なのです。 これは仕方のない話で , それらのプログ ラミング言語が設計されたころはまだコン ピュータの性能が低く , 画像表示が可能な 環境はまだ一般的ではありませんでした。 Java が図形や GUI をサポートしているのは , それらが使えるようになったあとに設計さ れたからです。また , 昔はインターネット 環境も整っていなかったため当然そんな機 能もなく , コンピュータの能力も低いため 何か付け足したいと思ってもできなかった のです。 プログラミング言語の目的の違いもあり ます。 BASIC は最初から PC のデスクトップ 環境を想定して作られています。しかし , c はシステムの記述のために開発され , ワ ンチッブマイコンや据え付け型のシステム などでも使えるよう , 最大公約数的な規格 しか決めていません。現に , C にはディレ TabIe 1 各言語における標準状態での性能比較 C BAS ℃ ( 注 ) Java 文字列の入出力 ファイル入出力 図形描画 〇 〇 〇 〇 〇 〇 GUI プログラム作成 x Fig. 1 プログラミング言語の仕様 ( 注ここでの BAS はⅥ su Basic ではなく J 旧規格の F ⅶ BAS ℃ ) ライブラリ 仕 文字表示 ファイル処理 etc.. 制御構造 関数定義 データ型 etC.. クトリを扱う関数さえいまだにありません。 C には標準で 15 個のヘッダファイルがあ り , この中で各種の関数が宣言されていま す。その中で実際に目に見える入出力を行 う関数はく stdio. h > に入っているものしかあ りません。 C + + にはもう少し多くのヘッダ が用意されていますが , その多くはデータ 構造の扱いを便利にするためのものであっ て , 入出力関係はやはり文字列の入出力し かサポートしていません。 コンバイラと非標準ライプラリ しかし W1ndows や Macintosh , あるいは X Window System 上のプログラムでは , 常に 画面描画をしています。そういう機能は言 語標準ではなく , コンパイラに付属するラ イプラリで行うことになります。 たとえば , VC + + をインストールすると M FC や ATL など多くのライプラリが入ってき ます。これを使って GUI の作成 , 図形描画 などを行います。これらは , C + + の <iostrea m > などで宣言されている関数と文法的に異 なっているわけではありません。ユーザ側 からは , 言語で規定されている標準ライプ ラリもコンパイラが提供するライプラリも , 同じ感覚で使うことができるのです。 ところで , 「コンパイラに付属するライ プラリ」といいましたが , ライプラリは必 ずしもコンパイラ特有のものではありませ ん。たとえば MFC というクラスライプラリ は , VC + + だけではなく他社のコンパイラに も付いてきます。もちろん , あとからライ プラリを追加することも可能です。実際に 有料 , 無料含めて多数のライプラリが存在 します。コンパイラ付属のものがいやなら そちらを使ってもいいわけです。 OS とデバイスドライバ さて , コンパイラのマニュアルを調べて も , やりたいことの実現方法がわからない ときがあります。たとえばサウンド機能な どは , コンパイラによっては提供されてい 困ったときの 解決策はどこにある ? ないかもしれません。できることは確実な のにライプラリに用意されていないといっ た場合の対処方法はいくつかあります。 1 つは , OS に直接働きかける方法です。 OS というものは何のためにあると思います か ? 教科書的にいえば「コンピュータの 資源 ( ディスク , CPU など ) を管理し , プロ グラムの実行を司る」となるのですが , プ ログラミングという観点から見ると OS は 「機能のかたまり」としての側面があります。 OS が用意している機能は , Wmdows の場合 API ( Application Programming lnterface) , UN Ⅸの場合はシステムコールと呼ばれて います。この機能をプログラムから呼び出 すことによって , できることはかなり広が ります。 OS の機能を呼び出す方法は各 OS に依存 します。 MS - DOS のころは特殊な命令を使 うか , あるいはプログラムの一部をアセン プリ言語で書く必要がありました。しかし UNIX や Windows では , それぞれライプラリ を整えているために C の関数呼び出しと同 じ感覚で利用が可能です。 ですが , たとえ OS の機能を使っても何で もできるというわけではありません。新種 の周辺機器 ( 最近だったらデジカメなど ) が 発売されたときなどは対応できないことが あります。原則的にはどんな周辺機器でも , 適切な窓口 ( I / 0 ポートなど ) に適切なタイ ミングで適切なデータの列を流し込んでや れば動くはずですが , それをプログラムの 側でやるのはあまりに煩雑でしよう。それ に OS によってはポートの使用が制限されて いて , 一般のプログラム ( アプリケーショ ン ) からは使えないことがあります。 そういう場合は , デバイスドライバを使 います。これはプログラムの一種ですが 通常のプログラムとは違って下請け的に働 き , 周辺機器とのやりとりの仲立ちをする ものです。 OS 自身も最終的には , デバイス ドライバを通して周辺機器を動かしていま す。アプリケーションから周辺機器の機能 を使うとすれば , 直接デバイスドライバに 特集プログラミング入門困ったときの解決策はどこにある ? 1 9
プログラミングのセオリー ちょっと長めに技術者をしていれば , 経 験がとても重要だということがわかる。た とえば設計技術に関しても , その経験が生 かされた設計とそうでないものでは実際に 完成した時点で大きな違いが出る。それは , たとえ小さいことでも , 経験によって事前 に対処されているさまざまな事柄が最終的 な形になるからだ。 ほんのちょっとした事柄の積み重ね , た だ知っている , 経験したことがあるという ことが , 結局は技術者の大切な能力となる。 経験を生かすということはどういうことか といえば , 結局はセオリーや定石といった 形に落ち着くのかもしれない。では , その セオリーや定石を学ぶためには , いったい どうすればいいのだろうか。 豊かな経験に裏打ちされた内容 本書『プログラミング作法』は , ご存じ 『プログラミング言語 C 』 (ISBN : 4-32 026 92-6 ) の著者の 1 人である Brian W. Kernigha n が RobPike とともに書いた , プログラミ ングの実践に関する書籍だ。 入門でも解説でも仕様でもなく , 実践の ノウハウを書いた書籍は , ためのセオリー ことプログラミングの分野に限ると , 思っ たよりも少ない。 その内容は , プログラミングスタイルか らアルゴリズム , データ構造 , 設計と実装 , デバッグおよびテスト , チューニング , 移 植性など , 幅広い範囲を網羅している。か といって内容が薄いかというと , そんなこ とはない。文章や構成がよくできており , わかりやすく論理的な説明があるため読み やすい印象がある。しかし汎用性の高い内 容に重点を絞ってあるため , むしろ全体と 『プログラミング作法』 プログラミング作法 THE PRACTICE OF PROGRAMMING し、 福崎俊博訳 日 ob Pike Brian W. Kemighan ASCII Brian W. Kernighan, 344 ペーシ , 2 , 800 円 アスキー 旧 BN4-7561-3649-4 Rob Pike 著 / 福崎俊博訳 してはひどく重い内容になっている。各所 に小問題も用意されており , 理解を助けて くれる。また , 各章の末尾にあげられた参 考文献も興味深い。どれも大切な文献ばか りで , 参考資料としてそろえておきたいも のばかりだ。 経験豊かな先輩からさまざまなノウハウ を教えてもらう。本書を読んでいると , そ ういう感覚を味わうことができる。 本書を読んで感じたことは , 経験の重み だ。デザインパターンを知ったときにも思 ったのだが , 個々人が問題から学んだこと は結局は普遍的な問題を扱っていることが 多く , 特定の解決方法としてまとめて共有 できるということだ。先端技術を学び続け ていくエンジニアの世界では , どうしても 過去の知識の蓄積 , 経験の共有といったこ とが軽んじられる傾向があるように思う。 実際には , 現場にいればいるほどまとめて おきたくても簡単なメモさえとれないこと が多いにれはたとえば企業的に重要視さ れないといった影響も大きいだろう ) 。 本書はその積み重ねの大切さをしつかり と教えてくれる。そしてそこから導き出さ れた現実的な , 机上の空論ではないノウハ ウを解決手段とともに提示してくれるのだ。 たとえば , 第 4 章のインタフェイスに関 する部分では , カンマ区切りフォーマット , いわゆる CSV の実装を例に話が進んでい く。いかにも誰でもやったことがある内容 にもかかわらず , ほとんどの人が多くのこ とを学ぶことができるだろう。 なお , Appendix として本書に登場したル ールがまとめてあるのだが , これがとても 重要な内容に思えるのは決して筆者だけで はないだろう。「悪いコードにコメントを 付けるな。書き直せ。」などの , 心に染み込 んで胸が痛くなる格言がずらりと並んでい て , 読むだけで平謝りしたくなるはずだ。 プログラマ必携の書物 なお , 同じく Brian W. Kernighan と P. J. Plauger ( 本誌の読者はよくご存じの Plaug er 氏だ ) の共著として , 共立出版から『ソフ トウェア作法』 (ISBN : 4-320-02142-8 ) , 『プログラム書法』 (ISBN : 4-32 圓 2085-5 ) と いう書籍も出ている。こちらも長い間プロ グラマのバイプル , 名著として知られてい る。 本書を読むなら , 間違いなく若ければ若 いほど , 早ければ早いほどいい。もっとも , 経験豊かなほうが本書に書いてあることの 重要性を実感することができるかもしれな 本書は , 設計から実際のプログ ラミングまで , およそ「プログラム」にかか わる人であれば必読 , 必携だと断言してよ い大切な書籍だ。常に傍らに置いておくべ ・問い合わせ先 ( 株 ) アスキー TEL 03-5351-8111 ( 代 ) http://www.ascii.co.jp/books/books/ き書物だといえるだろう。 Cmaga B00kends 凵 5
定期購読か新しくなりまし - ソフーンク バブリッシングの ' は 動動 インターネット ・お申し込みは専用ハガキかインターネットをご利用ください。 ・お申し込みいただいた内容確認のため、注文明細をお送りします。 ・郵便局またはコンビニエンスストアからお支払いください。 ( 初回配本後支払用紙を郵送します ) ・ホームページからはクレジットカードでのお支払いが可能です ・送付先を複数登録して、自宅や勤務先など、雑誌ごとに受け取る場所を指定できます。 お申し込み方法 お申し込みの前に必ず会員規約をお読みいただき、同意いただける場合のみお申し込みください。 巻末のハガキに必要事項をご記入のうえ、切手を貼らすに投函ください。 また、インターネットでは、エスビピーダイレクトホームページ (http://www.sbp-direct.com/ からお申し込みできます。 クレジットカードをご利用の場合はホームページよりお申し込みください。 お申し込み内容の確認 申込締切に間に合った 第一回酉鉢の数日後に振 のため、注文明細をお 号からお送りします。締 込用紙をお送りします。 送りします。ご確認く 切は発売日の 1 0 営業 日前 ( 土日祝日を除く ) ださい。 です。 0 専用ハガキ お支払い方法 お近くの郵便局または コンビニエンスストア でお支払いください。 手数料はかかりません。 専用ハガキまたはホー ムページからご注文く ださい。 お問い合わせ 【社屋移転のため、下記の通り住所、電話番号等が変更になりました。】 ソフトバンクバブリッシング株式会社定期購読センター 新住所〒 107-0052 東京都港区赤坂 4-13-13 TEL: 03-5549-1202 FAX: 03-5549-1212 E-mail: marketing@softbank.co.jp 今後とも弊社雑誌・書籍をご愛読いただけますようお願い申し上げます。 インターネットでの ソフトバンクバブリッシングダイレクトホームページ http://wwwsbp-direct.com/からお願いします。 お申し込みは SOFT BANK ソフトバンクバブリッシング株式会社 Pub ishing