Javaでなぜつくるのか 知っておきたいJavaプログラミングの基礎知識
今回は、現在の状況をメモリに保存しまた保存した状況を再生する機能、そして1ステップ戻す機能を追加します。さらに、アプリケーションの他にアプレットも作ってみました。
現在の状況を保存する時、必要となるデータは
です。この3つを配列に保存しその配列を返す関数saveMemory()をデータクラスに追加しましょう。この関数は、上の3つのデータ分のbyte型配列を確保してデータを書き込み配列を返すので以下のようになるでしょう。int型のstepについては、データを保存する配列dat[]がbyte型なのでストリームを作ってそこにstepを書き出してからストリームの内容をdat[]に書き出すようにしました。
public byte[] saveMemory() { // 現在の状況を配列に保存 byte dat[]; ByteArrayOutputStream out=new ByteArrayOutputStream(); DataOutputStream dout=new DataOutputStream(out); try { // ストリームにstepを書き出す dout.writeInt(step); } catch (IOException e) {} int size=12+width*height; dat=new byte[size]; // 保存用配列確保 // ストリームに書き出したstepをコピー System.arraycopy(out.toByteArray(),0,dat,0,4); try { dout.close(); out.close(); } catch (IOException e) {} // 現在のルールを保存 for (int i=0;i<8;i++) dat[4+i]=(byte)(rules[i]+1); // セルの状況を保存 System.arraycopy(lifes,0,dat,12,width*height); return dat; }
アプリケーションで現在のデータを保存する時には、保存用のbyte型配列を用意し、saveMemory()が返した配列をそこに代入します。例えば、ボタンbtSaveをクリックするとbyte型配列saveDatに現在の状況を保存するなら
if (e.getSource()==btSave) { // Saveボタン saveDat=ldat.saveMemory(); }
とします。これで、配列saveDatに現在の状況が保存できたので、次は配列から世代数やルール、セルの状態を設定する関数loadMemory()をデータクラスに定義しましょう。
public void loadMemory(byte dat[]) { // 配列の状況を再現 ByteArrayInputStream bin=new ByteArrayInputStream(dat); DataInputStream din=new DataInputStream(bin); // Stepを取得 try { step=din.readInt(); } catch (IOException e) {} try { din.close(); bin.close(); } catch (IOException e) {} // ルールを取得 for (int i=0;i<8;i++) rules[i]=(int)(dat[4+i]-1); // セルの状態を取得 System.arraycopy(dat,12,lifes,0,width*height); // 生物数を計算 nlife=0; for (int i=0;i<width*height;i++) nlife+=lifes[i]; }
アプリケーションで保存した状況を再生するには、このloadMemory()に先ほど作成したsaveDat[]を渡して世代数や生物数、ルール、セルの状態を描きなおします。
if (e.getSource()==btLoad) { // Loadボタン // データクラスに保存しておいた配列を渡す ldat.loadMemory(saveDat); // 現在の状況を表示 drawState(); rl.setRules(ldat.getRules()); disp.repaint(); }
データクラスの世代更新関数next()では、処理の前に現在のセルつまり更新前のセルをblifes[]に退避していました。blifes[]は世代更新後も更新前の状態をそのまま保持していますので、戻る機能はこのblifes[]をセル配列lifes[]にコピーする事で実現しましょう。
public void back() { // 1世代戻す System.arraycopy(blifes,0,lifes,0,width*height); step--; nlife=0; for (int i=0;i<width*height;i++) nlife+=lifes[i]; }
アプリケーションの方では、一度世代を進めたら「戻る」機能を呼び出すbtBackを有効化します。そして、戻るを使ったりメモリの状況を再現したら無効化する。これでblifes[]に1世代前の状況が入っている時だけbtBackが有効になるでしょう。
これまで作ってきたデータクラスやパネルクラスをアプレットにしてみます。基本的には、アプリケーションクラスに代わるアプレットクラスjlife4を定義し、アプリケーションクラスのコンストラクタで行っていた初期化をinit()で行えば良いので、それほど手間はかかりません。ただし、アプリケーションクラスを参照している部分をアプレットを参照するように変更したりアプリケーションの終了処理を除いたり、といった修正は必要ですが。
このアプレットの実行にはJDK1.1x以上の実行環境が必要です(IE4以上推奨)。
ソースファイルをCLife4.javaというファイル名にしてJDK1.1以上でコンパイルし、CLife4.classを実行してください。Saveボタンで現在の状況を記憶しLoadボタンで再生できます。