さて、今日から3回かけてライフゲームの実際の動きを書いていきます。今後の予定は下の通りです。
まず今日は盤面を記憶させる部分です。今回作るライフゲームの盤面は30×40=1200マスもあります。これをプログラムによって計算し、1マス目から順に書き換えていくと、当然2マス目を計算する時には1マス目はすでに書き換わっており、正しく計算することができなくなります。このため、計算に先だって、セルの状況を記憶しておく必要があります。
さて、どうやって保存するかです。いろいろな方法がありますが、今回は2次元配列というものを使ってみたいと思います。2次元配列とは、「配列名(番号1, 番号2)」という形を取り、1つの配列の中で番号を変えてやることで、複数の値を代入することができるものです。ちなみに1次元配列の場合は「配列名(番号)」という形になります。一見すると1次元配列の方が簡単そうですが、今回の場合エクセルのセルの状況を記憶するため、セルの行番号と列番号をそのまま番号1・番号2に使用できた方が分かりやすいです。さらにエクセルのセルの情報を取得する際には「Cells(行番号, 列番号)」という形になるので、ほぼ同じ形で書くことができます。
今回は共通の処理として登録するので、コードは標準モジュールに書きます。Alt+F11でVBEを開き、VBAProjectのところの標準モジュールというディレクトリを開きます。すると、少し前に定数を定義したコードがModule1というところに保存されているはずなので、そこを開きます。この処理には結果の取得は必要ないので、サブプロシージャとして作成します。また、プロシージャの名前は「nextGeneration」とでもしておきましょう。先日作成した定数の定義の下に「Public Sub nextGeneration()」と入力し、エンターを押します。すると2行程下に「End Sub」と自動で入力されるはずです。この間に書いた処理がnextGenerationを実行したときに処理されるプログラムとなります。
‘ここの処理がnextGenerationの中身ということになる。
End Sub
次に、行番号・列番号に使用する変数を定義します。行をy、列をxとしましょう。もちろん整数の値を使いますので、もう何度か出てきていますが、Long型で定義します。また、
Dim x As Long
次に配列を定義します。2次元配列の定義は「Dim 配列名(最大の番号1, 最大の番号2) AS データ型」という形で宣言します。配列名は簡単に「memory」としておきましょうか。さて、この最大値を決める際に、作っておいた定数が活きてくるワケですね。ただしここでは、大人の事情により、それぞれ1大きい数を指定しましょう。行は「YMAX + 1」列は「XMAX + 1」とします。配列の番号は0~定義した最大の番号となります。なので、セルのサイズより小さい方も大きい方も1マスずつ大きく設定してある状態となります。
なぜ大きく設定するかというと、ライフゲームでは次の世代に書き換える際に、隣接する8マス分のセルの状態を見ます。この時端のセルはセルの外側の値を準備しておかないと、エラーが発生してしまいます。このため、1マスぶんだけ広く配列を準備しておくと便利なワケです。
次に型についてですが、これは整数型にしておくのが便利かと思います。これも次の世代に書き換える際の話ですが、隣接する8マスの「生」のセルを数えることになります。なので、「生」の状態を1、「死」の状態を0としておけば、単純な足し算で「生」のセルを数えることができます。
そんなワケで定義は下のようになります。
それでは、これから2次元配列にセルの状態を格納していきましょう。しかし、縦幅30マス・横幅40マスもあります。単純に30×40=1200です。1200回もこれを繰り返します。こういう処理ってのは人間は苦手ですが、まさにパソコンの得意とするところです。プログラムのもっとも活躍できる場なワケです。さて、これを書くにあたり、状態を確認し、配列に格納する処理を1200行書けば、それでも動くワケですが、それでは芸がありません。繰り返し処理を使いましょう。
基本的な繰り返し処理には「Do~Loop」と「For~Next」があります。条件を見ながら繰り返す時には「Do~Loop」を使い、規定回数を繰り返す時には「For~Next」を使うことが多いです。今回の場合、1200回繰り返すコトが決まっているので、「For~Next」を使います。「For~Next」は下のような書き方をします。
‘変数の値が初期値から始まって1ずつ増えながら実行され、最終の値で実行されたら終了
Next
さて、先ほど定義した変数y, xを使う時がきました。まず、yを1から始めて、YMAXになるまで増やしながら、プログラムを実行すると、1行目からYMAX行目までのプログラムを実行することができます。
‘1行ごとに処理を実行
Next
1行ごとに処理を実行するプログラムの中にxとXMAXを使って、1列ごとに処理を実行すれば、すべてのセルに対して処理を実行することができます。
For x= 1 to XMAX
‘1マスずつ処理を実行
Next
Next
さぁ、最後は処理の中身です。セルの状態を取得する際には「Cells(行, 列)」の形で書くことは上で書きました。そして、赤く塗りつぶされている場合にmemory配列に1を代入すれば良いだけです。If文を使って、簡単に実装できますね。
If Cells(y, x).Interior.Color = RGB(255, 0, 0) Then memory(y, x) = 1
最終的な形を定義部分からすべて書くと、下のようになります。
Dim y As Long
Dim x As Long
Dim memory(YMAX + 1, XMAX + 1) As Long
For y= 1 to YMAX
For x= 1 to XMAX
If Cells(y, x).Interior.Color = RGB(255, 0, 0) Then memory(y, x) = 1
Next
Next
End Sub
これで、盤面を記憶する部分が完成しました。