私の「プロの開発者」としてのキャリアは、同年代の開発者よりちょっと長いと思います。当時、読者からの投稿プログラムを掲載している雑誌がありました。そこに最初に送った短いゲームプログラムが採用されたのです。
中学生のころの話です。自分の作ったプログラムで最初にお金を稼いだのはそのときです。初めてパソコンを買って、1年たたないくらいの時期の出来事でした。
その後縁があって雑誌の編集部に遊びに行き、定期的にお邪魔しては、プログラムを作って掲載してもらうようになりました。中学生にとって、かなりいいお小遣い稼ぎになったように記憶しています。
当時のマシンは非力で、開発環境もいまほど充実してはいませんでした。多くのゲームがPCに付属していたBASICというプログラミング言語を使って作られていました。当時のBASICは機能があまり豊富でなく、かつ処理速度に問題がある場合が多く、ちょっと凝ったことをしようと思うと機械語を使う必要がありました。
CPUが直接解釈できるコードを組み立てて、コンピュータを直接操作するのです。CPUを直接操作するので、コンピュータの性能をほぼ限界まで利用することができました。
私がお小遣いを稼ぐためには、一般の投稿者と比べてより目を引くゲームを作る必要があります。すべてBASICで書かれた比較的遅いゲームに対して、素早く動くゲームは十分に魅力的です。そこで、私は「重たい処理を機械語でサブルーチン化して残りをBASICで書く」という選択をするようになりました。
いま風にいうなら、BASICを糊(Glue)言語として使っていたわけですが、もちろん当時そのような言葉は当然ありませんでした。当然の選択として、似たような方法論を使っていたわけですね。
ビットマップディスプレイ上に線を引く
あるとき、私は「インタラクティブな3Dゲーム」を作ろうと思いました。当時のPCのグラフィック機能はとても貧弱で、線を使って「物体らしく見えるもの」を表現するのが精いっぱいでした。
いわゆるワイヤーフレームで3Dを表現しようとしていたのですが、BASICの持つ線分描画機能(LINE文)があまり高速でなく、ゲームとして楽しめるような速度感を実現できませんでした。
機械語を使えばより速く線分を描画できることは直感的に分かりましたので、専用の線分描画サブルーチンを作ることにしました。ビットマップディスプレイ上に線分を引くためには、与えられた始点と終点をドットでつなぐ必要があります。方法は何種類か考えられます。
最も素朴な方法は、線分の方程式を使ってドットを打つ点の座標を計算する方法でしょうか。線分の始点と終点の座標が分かれば傾きが分かります。傾きが分かれば、X座標からY座標を、または逆の変換を行う方程式を作ることができます。この方法の難点は実数演算を伴うことです。当時のPCにとって実数演算はとてもコストの掛かる処理でしたので、あまり現実的ではありません。
ブレゼンハムのアルゴリズム
ビットマップ上に線分を描画するための方法として「ブレゼンハム(Bresenham)のアルゴリズム」というものがあります。整数演算だけを利用して線分を描画できるため、高速に処理できるのが特徴のアルゴリズムです。
例えば、グラフィック画面上の画像(0,0)から(30,10)に線分を引きたいとします。横方向(X軸)の差の方が、縦方向の差(Y軸)の差より大きい線を描くことになります。X軸の正方向に3つドットを打つごとに、Y軸の正方向に1つ増やせばきれいな線分が引けるはずです。
このように線を引くために、ブレゼンハムのアルゴリズムではカウンタを1つ利用します。線分の始点と終点のX座標の差を「Δ(デルタ)X」とし、Y座標の差を「ΔY」とします。
点を打つとき、X軸を1つ増やすごとにカウンタにΔYを足していき、ΔXの値を超えたらY軸の座標を増やします。そのとき、カウンタからはΔXを引いておきます。こうすると目的どおりの線が引けるのです。演算の過程では整数しか使っていませんので、高速に線分を描画できます。
この法則を以下のように一般化すると、どんな線分でも引けるようになります。
- 線を引くとき、線分のX軸、Y軸の座標差が大きい方を1ずつ増減する
- 座標差が小さい方について、カウンタを使って増減のタイミングを調整する。このとき、カウンタには差の小さい方を加算する
- 差の大きい方の数値を超えたら座標差が小さい方を1ずつ増減する。カウンタからは、差の大きい方の数値を引いてリセットする
また、実際にやってみると分かりますが、カウンタの初期値を上限数の半分にしておくと、より滑らかに見える線を引くことができます。
低レベルプログラミングで学んだコンピュータの動作原理
当時、私がやっていたプログラミングは万事が万事このような調子でした。当時のPCはいまの携帯電話よりずっと低機能だったので、かなり低レベルなところから始める必要があったのです。
低レベルなことをやるのですから、いまから思い返すと時間もかかりましたし、非効率なことも多かったのですが、いいこともありました。コンピュータの動く仕組みの奥底に直に触れることができたのです。
例えば、当時私が持っていたPCで音を鳴らすためには、CPUからスピーカーをコントロールしてパルス(プッという音)を鳴らす方法しかありませんでした。パルスを短い間隔で鳴らすと高い音に聞こえ、長い間隔で鳴らすと低い音に聞こえます。つまり音というのはパルスの集合体として表現でき、パルスの間隔を変えると音程を決められるわけです。
コンピュータの画面上で滑らかに見える線も実はドットの集合体です。私の持っていたPCではドットごとに8色のうち1色しか割り当てられませんでしたが、色というのは光の三原色を組み合わせたものだということを実感できました。8色を巧みに組み合わせて「ディザリング」すると、中間色を表現できることにも素直に感動した覚えがあります。
CPUのレジスタだけを使って処理を実行するように書き換えることで、プログラムの処理速度を高速化できます。メモリアクセスの方が時間がかかるということを実感することができました。もともと低スペックなので、下手に書くと何時間たっても終わらないプログラムが出来上がります。アルゴリズムの重要さを肌で実感することができたのです。
コンピュータの動作原理について知ることは、開発者にとってとても重要なスキルです。アプリケーションのパフォーマンスチューニングをしたり、データベースのテーブル設計をしたり、アプリケーションのスケーラビリティを確保したりといったことをするときにこの種の知識は必須といってよいかもしれません。
いまよりずっと感受性の強い時期に、つまずきながらコンピュータの基本を学ぶ機会がありました。当時学んだことは、いまもとても役に立っています。
時代が変わって、PCは大容量のキャッシュを備えた高速なCPUと豊富なストレージ、メディアデータを扱う機能を持つようになりました。しかし、基本的なアーキテクチャや動作原理はほとんど変わりません。昔と同じ仕組みで動いていますので、内部で何が起こっているのか、だいたいのイメージをつかむことができます。
私の若いころに比べると、いまの開発者はとても恵まれていると思います。高機能なPCが簡単に手に入ります。半面、コンピュータの奥底に触れる機会がずっと減っているように思います。昔のように、CPUのレジスタに触れたり、ハードウェアを直接操作してパルスを組み立てて音を鳴らしたりする機会はいまの開発者にはほとんどないはずです。
そのような環境で、コンピュータの動作原理を学ぶことはできるのでしょうか。コンピュータパワーを含めすべての資源は有限です。多くの開発者がコンピュータの動作原理を知らず、富豪的なプログラミングばかりがはびこる世界が来るのだろうか。漠然とではありますが、ちょっとだけ不安感を抱いていた時期がありました。
好奇心や探求心を忘れずに
あるとき、ソーシャルブックマークを見ていたら、とても面白いものを見つけました。Webブラウザ上にビットマップの線を引くという試みをしている方を見つけたのです。CSSの固定位置要素とJavaScriptを使って、線分描画の手法にはブレゼンハムのアルゴリズムを使っていました。
私が中学生のころにやっていたこととまったく同じことをWebブラウザの上で実現している人を見つけたこともあり、時代を超えて心が通じ合ったような気がして、ちょっと共感を覚えました。当時の私もこの方も、同じような好奇心や探求心を持ってプログラムを作っていたはずです。
それ以来、私はちょっと考え方を変えるようになりました。私がコンピュータについて学べたのは、限定的な状況があったからではなく、好奇心や探求心を絶やすことなく、いろいろなプログラムを作り続けていたからだと思うようになりました。
いまのPCは昔に比べてより多くの種類のデータを扱うことができます。インターネットを使えばさまざまな種類のデータが手に入りますし、開発環境も無料で手に入ります。いろんな種類の興味をきっかけに、より深い領域に入っていけるチャンスが開けているわけです。
Webブラウザ上にビットマップの線を引くという試みは、「多くのWebブラウザで動作するように」というモチベーションから生まれたそうです。PCを使って何でもできる時代になっても、限定的な状況は生まれ得るし、探求心さえあれば、コンピュータの動作原理に触れるような体験をすることはできるのだなあと納得したものでした。
大切なことは、探求心や好奇心をふんだんに発揮して、トライ&エラーを繰り返しながらいろいろなものを作り続けることです。
Coding Edgeフォーラム トップページ |
Coding Edgeお勧め記事 |
いまさらアルゴリズムを学ぶ意味 コーディングに役立つ! アルゴリズムの基本(1) コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう |
|
Zope 3の魅力に迫る Zope 3とは何ぞや?(1) Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか? |
|
貧弱環境プログラミングのススメ 柴田 淳のコーディング天国 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く? |
|
Haskellプログラミングの楽しみ方 のんびりHaskell(1) 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう |
|
ちょっと変わったLisp入門 Gaucheでメタプログラミング(1) Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう |
|
- プログラムの実行はどのようにして行われるのか、Linuxカーネルのコードから探る (2017/7/20)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。最終回は、Linuxカーネルの中では、プログラムの起動時にはどのような処理が行われているのかを探る - エンジニアならC言語プログラムの終わりに呼び出されるexit()の中身分かってますよね? (2017/7/13)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、プログラムの終わりに呼び出されるexit()の中身を探る - VBAにおけるFileDialog操作の基本&ドライブの空き容量、ファイルのサイズやタイムスタンプの取得方法 (2017/7/10)
指定したドライブの空き容量、ファイルのタイムスタンプや属性を取得する方法、FileDialog/エクスプローラー操作の基本を紹介します - さらば残業! 面倒くさいエクセル業務を楽にする「Excel VBA」とは (2017/7/6)
日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。本稿では、業務で使うことが多い「Microsoft Excel」で使えるVBAを紹介する。※ショートカットキー、アクセスキーの解説あり
|
|