Ccmmutty logo
Commutty IT
0 pv5 min read

プログラミングはなぜ「難しい」のか あるいはコンピュータは思考していないという話

https://cdn.magicode.io/media/notebox/blob_9wZacr1
プログラミング言語のマニュアルを読んで「if文で条件分岐できる」「for文でループできる」といったことを学び、サンプルプログラムを動かしてみたりいじってみたりはできる。しかしそこで「ではシューティングゲームを作ってみましょう」など具体的な目的を与えられるとピタリと手が止まってしまう。そんな方は多いと思います。 この記事ではなぜそんな現象が起こるのか解説していきます。

コンピュータ≠脳

そもそも「プログラム」とは何でしょうか。「プログラム」という単語は「運動会のプログラム」と使われたりもするように、順序、手順を意味します。これはコンピュータの「プログラム」でも同じです。コンピュータは人間によって書かれた「変数Xに10を代入しろ」「変数Xと変数Yの大きさを比較しYの方が大きければこの命令を実行しろ」といった「手順」を淡々と実行しているだけです。だからプログラムを書きたければ単にコンピュータが実行すべき手順を淡々と書けばいいだけです。問題はその「手順」を人間は無意識にやっていることです。 どういうことか? 例えばあなたが家族と一緒に食事をしていて醤油が必要になったとき醤油差しが少し遠くにあったとします。このとき「醤油取って」と言えば近くの人が醤油を取ってきてくれるでしょう。このとき間違っても「醤油取って。単に持つだけじゃなくこっちに運んでって意味だよ。運ぶ途中で傾けてこぼしちゃダメだよ。人や皿や食べ物に当たらないようにしないとダメだよ」などと言う必要はありません。しかしそれを全部書き出さなければいけないのがプログラミングなんです
よく脳をコンピュータに例えたり逆にコンピュータを脳に例えたりしますがこの2つは情報の処理方法が全く異なります。例えばコンピュータは人間なら長時間かかる計算を一瞬でやってのけます。一方で「顔を認識する」「声で頼み事をする」といった人間なら子供でもできることがコンピュータは長い間できませんでした。コンピュータというのは(電子部品までさかのぼると)「A端子とB端子両方に電流が流れたときだけ電流を出力する」「A端子とB端子どちらか一方に電流が流れたときだけ電流を出力する」といった電子回路の集合体で、この電流のオンオフと二進法(0と1だけで数値を表現)を対応させることで数値計算(だけ)は光の速さでできるようにしただけで、それ以外はからっきしなのです。
コンピュータを相手にするのはちょうど発達障害の子供を相手にするようなものです。電話で「お母さんいる?」と聞くと「いる」と答える。しばしの沈黙の後「お母さんと変わってくれる?」と聞くとようやく変わってくれる。コンピュータはこの発達障害の子供のようなもので「相手の質問の意図は何か?」「相手は何を求めているか?」を一切考えてくれません。 人間なら「醤油取って」の例からもわかるように全く無意識の内に相手の意図や注意しなければいけないことを考えてくれます。例えば会社で「コピー10枚取って」と指示したら当然コピー10枚取るだけでなくそれ(と原本)を持って帰って来て何なら会議のメンバーに配るところまでやってくれるでしょう。電話で「○○さんいらっしゃいますか?」と聞かれたら当然その人に用があるのだということを推測し、電話を変わったり後でこちらからかけ直すように伝えてくれるでしょう。 人間は常にこのような思考(推測)を全く無意識の内に実行しており当然相手もそのように思考してくれているだろうと考えて会話や命令(お願い)をしています。だからそれらを全くしてくれないコンピュータを相手にすると何をすればいいかわからず呆然としてしまうのです。 ちなみにビル・ゲイツやスティーブ・ジョブズなど著名なエンジニアが発達障害という話があります。発達障害は「空気や行間が読めない」「ジョークや皮肉を理解できず言葉をそのままの意味で受け取る」という特徴がありますが、行間を読まず言われたことだけをそのまま実行するのはコンピュータと同じです。発達障害の人がプログラマに向いてるのは普通の人よりも考え方がコンピュータに近いからだと思われます。

すべてを明文化する

プログラムは「思ったように」は動かない。「書いたとおりに」動く。という言葉がありますが、上記のようにコンピュータはこちらの意図を汲んではくれないので「こういう動作をして欲しい」と無意識に考えていることをすべて書き出さなければいけません。最初に例としてあげた(縦スクロール)シューティングゲームなら以下のようになります。
  • まず画像を描画できる必要がある
  • 自機と敵機を配置する
  • 「←」「→」「↑」 「↓」キーを押した時自機をそちらの方向に移動させる
    • ただし画面外に出てしまう場合は移動しない
  • 「z」キーを押すと弾を生成する。位置は自機の真ん中の前方。また、弾を「弾リスト」に加える。
  • 「弾リスト」のすべての弾に対して以下の処理を実行
    • 弾は時間経過に従い上に移動していき、敵機と重なると敵機を破壊し、また自身は消滅し、弾リストから除かれる。画面外に出た弾も除かれる
    • 弾が当たった敵機は爆発の画像に切り替えた後、消滅する。
  • 弾は連続して発射できるようにするとビームのようになってしまうので一定間隔で発射するようにする
  • 自機と敵機が重なったときは自機の画像を爆発の画像に切り替えゲームオーバーとする
具体的なプログラムは以下のような形になります(カンタンのため敵機は一機としています)。
ウインドウサイズは横100縦200とする
5x5サイズのPictureBox(C#の場合。言語によって異なる)を生成。自機の画像を貼り付ける
5x5サイズのPictureBoxを生成。敵機の画像を貼り付ける
自機を(47,194)に配置
敵機を(47,0)に配置

弾リストを作成
count = 0
前回発射時countにintの最小値をセット

ループ:
   「←」キーが押されている時
        自機のx座標が1以上なら、自機のx座標を-1
   「→」キーが押されている時
        自機のx座標が94以下なら、自機のx座標を+1
   「↑」キーが押されている時
        自機のy座標が6以上なら、自機のy座標を-1
   「↓」キーが押されている時
        自機のy座標が194以下なら、自機のy座標を+1
    
    敵機のy座標を+1
    自機と敵機を重なり判定し、重なっていたなら自機の画像を爆発に置き換えて、「GAME OVER」と表示。ループを抜ける

    「z」キーが押されている時
        count-前回発射時countが4以上なら、//弾を一定間隔で発射するため
            1x1サイズの弾PictureBoxを生成。黄色で塗りつぶし有りで円を描画。
            位置は(自機のx座標+2, 自機のy座標-1)。弾リストに追加。
            前回発射時countにcountを代入
     
    弾リストをループ:
        弾と敵機を重なり判定し、重なっていたら弾を破壊し、弾リストから除外。敵機を爆発画像に置き換えて、「GAME CLEAR」と表示しループを抜ける。
        弾のy座標を-1
        弾のy座標がマイナスなら弾を破壊、弾リストから除外する。

    count = count + 1
    0.05秒、待機

※重なり判定
    少し複雑なので https://qiita.com/hp0me/items/57f901e9b0babe1a320e を参照してください
このように「何をすればいいか」を明文化できたなら後はそれをプログラミング言語に置き換えるだけです。
以上を読んで「やっぱりプログラミングは難しい」と思う方もいるかも知れませんが、「コンピュータはこちらの意図を察してくれない」ということを意識し、試行錯誤を繰り返せば(多分)誰でもプログラミングできるようになると思います。

補足:プログラミングを食わず嫌いしてる方へ

まず最初に言っておくとプログラミングをする上で理系である必要はありません。確かに高速化や独自の人工知能を作ったりする場合はコンピュータ科学や数学の知識が必要となりますが、普通のプログラム(例えばToDoアプリ)を書くだけなら特別な知識はいりません。また、「英語がわからないとダメなんでしょ?」と思ってる方もいるかも知れませんが、ifやforなど少数の単語の機能さえ覚えれば英語の知識もいりません。有名な言語には日本語の解説もついてますし、何なら日本語プログラミング言語というのもあります。

Discussion

コメントにはログインが必要です。