前置き
最近森博嗣先生の本を読んだという記事を書きました。
それで思い出したのですが、人妻(というか私の妻)と0から学ぶプログラム入門ということで、Processingという言語を使って「すべてがFになる」に出てくるプログラムに関する記事をかいてずっと放置していた(実に半年くらい)の思い出したのでせっかくなので公開します。
そして、はてなさん 今週のお題「最近おもしろかった本」って、書いたばっかりだって!いつもながらタイミング悪すぎ!!
ちなみに前回の記事は以下。
すべてがFになる
今回つくるプログラムは、森博嗣さんの「すべてがFになる」という小説のトリックの再現になります。というわけで、完全にトリックのネタバレになりますので、小説・漫画・ドラマ・アニメ(来期開始予定)を事前知識無しで楽しみたいと言う方は続きを読まずに下記Amazonリンクで購入をオススメします。もちろんそこらへんの本屋で買っても、図書館で読んでもOKです。
- 作者: 森博嗣
- 出版社/メーカー: 講談社
- 発売日: 1998/12/11
- メディア: 文庫
- 購入: 16人 クリック: 241回
- この商品を含むブログ (588件) を見る
- 作者: 森博嗣,浅田寅ヲ
- 出版社/メーカー: 幻冬舎コミックス
- 発売日: 2002/02
- メディア: コミック
- 購入: 3人 クリック: 92回
- この商品を含むブログ (48件) を見る
ネタバレOKの人だけ続きを読むをクリック下さい。
Processingで数字を扱う
まずはProcessingで数字を扱う方法です。今回は、整数と小数の使い方を覚えます。整数を扱ったプログラムは以下になります。
void setup() { size(200,200); } void draw() { int x; x = 1; int y; y = 2; int z; z = x + y; println(x); println(y); println(z); }
int x というのが、xという整数の変数を表します。変数と言うのはデータを格納出来る箱のようなもので、その前のintはインテジャ(integer)、すなわち整数を表します。int xは整数を入れられる箱なわけです。
その後の x = 1 でxに1という数字が代入されます。同じように yに2を入れて z に x + yを入れてやります。するとどうなるかというと、xは1、yは2、zは1+2で3となります。確かめるために、x,y,zの中身を見てやりましょう。 変数の中身をみるには、printlnという関数を使います。println(x)とするとxの中身をみれます。
試しに上記のプログラムを実行すると、1,2,3という表示が下の方に何度も出て来るはずです。一度だけでなく何度も表示されるのは前回学習した通り、draw関数の中は何度も繰り返し実行されるからです。
このままだと、何がなんだかわからないという人は、以下のように修正してみましょう。
void setup() { size(200,200); } void draw() { int x; x = 1; int y; y = 2; int z; z = x + y; println("x = " + x); println("y = " + y); println("z = " +z); }
println("ここに好きな文字")というようにかくことで、好きな文字を表示させることができます。後ろに + xとするとその文字のあとに見たい数字を表示できます。これで実行結果は以下の表示が繰り返し表示されることになります。
x = 1
y = 2
z = 3
OK?
もちろん、 z = x - yで引き算もできますし、x × yの掛け算したいときは z = x * y、x ÷ yの割り算したい時は z = x / y でできます。
グローバル変数とローカル変数
では次に時間とともに変数の数を増やしていきたいと思います。例えば x という変数を1増やしたい時は以下のような3通りの書き方があります。一番下の書き方は1増やすとき限定の書き方です。
x = x +1; x += 1; x++;
何故3通りもあるかというと…よく分からないです。使う分には一つ覚えればよいのですが、他の人のプログラム見る時もあるので3つとも覚えておきましょう。前回 draw の中は繰り返し実行されるということを学習したので、以下のようにかけばxが増えていくはず…
void setup() { size(200,200); } void draw() { int x; x = 0; x += 1; println("x = " + x); }
といいたいところですが、プログラムを実行すると x = 1がずっと表示されます。何故かと言うと毎回 x = 0;という行で x = 0にリセットされてしまうからです。
ここで思い出して欲しいのは、setupの中は一度だけ実行されるということ。じゃあx=0;をsetupに移動してやりましょう。
void setup() { size(200,200); x = 0; } void draw() { int x; x += 1; println("x = " + x); }
これで完璧!と思いきや、「The field Component.x is not visible」という謎のエラー。これはxなんて変数は無いぞということを表しています。何故エラーになるかと言うと、int x;は drawの中にかかれていますが、これはsetupの中では使うことができないのです。
じゃあどうすればいいの!というと、カッコの外に出してやればよいのです。
int x; void setup() { size(200,200); x = 0; } void draw() { x += 1; println("x = " + x); }
こうやって x という変数をカッコの外で宣言することで、setupでもdrawでも使うことができます。実行してみると、ちゃんとxが1ずつ増え続けるプログラムができました。こういう、どこでも使えるような変数のことをグローバル変数といいます。一方drawとかsetupのカッコの中で宣言される変数をローカル変数といいます。グローバル変数便利なのでローカル変数なんてけちくさい物使わずガンガン使えばいいじゃんと思えるのですが、プログラムが大規模になると後で色々困ってしまったりするのですが、それはまた別の話。とりあえずガンガン使えばよいです。
あ、ちなみに何度か出ているvoid draw(){}とかvoid setup(){}の固まりを関数というのでここで覚えておいて下さい。関数の中がローカル、外がグローバルね。
条件分岐
ある特定の条件で、特定の命令を実行したいときは条件分岐と呼ばれるものを使います。例えば上のプログラムでカウント増やしていき10になったらメッセージを表示するプログラムを作りましょう。具体的には以下です。
int x; void setup() { size(200,200); x = 0; } void draw() { x += 1; println("x=" +x ); if(x == 10){ println("テスト"); noLoop(); } }
実行すると xが1ずつカウントアップしていき、10になった時点で 「テスト」と表示されてループが止まります。
if(x == 10){}というのが条件分岐の部分です。これだと xが10になったときだけカッコ{}の中の命令が実行されます。イコール(=)が1つじゃなくて2つなのに注意して下さい。理由はあんまり深く考えずにそういうものだと覚えて下さい。
カッコの中のprintln("テスト");で「テスト」という文字を表示する命令で、noLoop();という命令がループを止める命令です。noLoop();を省略すると、カウントがとまらずずっとカウントが続きます。
プログラム「すべてがFになる」
じゃあここで「すべてがFになる」のクライマックス、犀川先生がレッドマジックというOS(ドラマだとデボラ)のソースコード(プログラムのリスト)を調べるシーンを原作の小説から引用してみます。
「違う……。インクリメントイコールのはずだ」
「変数型は?」島田が聞く。「このまま見て行っても何百とあるわ……。きりがない」
「たぶん、インテジャだ」
「そう、そういえば……」途中で、島田文子が言った。「メールシステムをチェックしているとき、意味のわからないif分が、一行だけあったわ」
「変数の定義部分は?」と犀川の厳しい声。
またリストが流れる。
「グローバルの……、えっと、スタティックですね。インテジャだわ」島田が答えた。
これで、犀川先生はレッドマジックというOSのプログラムにトリック(トロイの木馬)が仕掛けられていることに気づいたのです。会話で出て来たインクリメントイコールは += のこと、インテジャはint(整数)、if文、グローバル変数。ここまで来たみなさんなら大体どんなプログラムなのか想像つきますね。
本来のプログラムは1時間に1ずつ増加し、65536(16進数でFFFF)になったとき実行されるプログラムなのですが、これだと7.5年程度待つ必要があるので、今回は1秒に60ずつ増加し、255(16進数でFF)になったら実行されるプログラムにしましょう。これなら4秒程度で実行されるので、気が短い人でも大丈夫です(drawの中はデフォルトで1秒に60回実行されます)。具体的には以下です。
int x; void setup() { // size(200,200); x = 0; } void draw() { x += 1; println("x=" +x ); if(x == 255){ println("すべてがFになる"); noLoop(); } }
実行すると4秒程度で「すべてがFになる」と表示されます。レッドマジックにもこんなようなプログラムがどこかに紛れていたというわけです。
宿題
何でもよいから計算するプログラムを書いてみましょう!