import java.applet.*;
import java.awt.*;
public class LifeGame extends Applet implements Runnable{
final int sx = 80; //横のセルの数
final int sy = 80; //縦のセルの数
final int z = 6; //画面表示の倍率
final int ey = 40; //操作表示部分
final int RectSize = z-2; //セルの描画サイズ
final Color BackGroundColor = Color.darkGray; //背景色
final Color ForeGroundColor = Color.lightGray; //前景色
final Color ColorOfAliveCell = Color.blue; //生きているセルの色
final Color ColorOfVacantCell = Color.yellow; //空のセルの色
final boolean alive = true; //セルの状態のフラグ
final boolean dead = false;
boolean cell[][] = new boolean [sx][sy]; //現在のセルの状況の配列
boolean oldcell[][] = new boolean [sx][sy]; //前のセルの状況の配列
byte cellcounter[][] = new byte [sx][sy]; //周りのセルの状況の配列
double noudo = 0.3; //初期画面でのセルの比率
static int die = 1; //周囲が少なくて死ぬ数
static int unchange = 2; //変化しない数
static int reproduce = 3; //セルが増える数
Thread th; //スレッド
boolean wait; //待機状況かどうかを示すフラグ
public void start(){
th = new Thread(this);
th.start();
}
public void run(){
while(th != null){ //スレッドが生きている限り
Life(); //表示
try{
th.sleep(100);
} catch(InterruptedException e){}
}
}
public void stop(){
th.stop();
th = null;
}
public void init(){
wait = true; //スレッドの実行を押さえる
for(int i = 0; i < sx; i++){ //セル情報の初期化
for(int j = 0; j < sy; j++){
cell[i][j] = oldcell[i][j]
= ((Math.random() < noudo) ? alive : dead);
cellcounter[i][j] = 0;
}
}
resize(sx*z,sy*z+ey); //画面サイズの設定
setForeground(ForeGroundColor); //前景色設定
setBackground(BackGroundColor);
setLayout(new BorderLayout()); //レイアウト形式指定
Panel p = new Panel(); //コントロールを配置するパネル
p.setLayout(new FlowLayout()); //コントロールの配置方式
add("South", p); //画面の一番下に表示
p.add(new Button("run")); //実行制御ボタンの設定
p.add(new Button("stop"));
p.add(new Button("continue"));
Choice c = new Choice(); //ルール設定リストの設定
c.addItem("normal");
c.addItem("type 2");
c.addItem("type 3");
c.addItem("type 4");
p.add(c);
c = new Choice(); //セルの濃度設定リストの設定
c.addItem("low");
c.addItem("middle");
c.addItem("high");
p.add(c);
wait = false; //スレッドの動作の再開
}
public void paint(Graphics g){
wait = true; //スレッドでの書き直しを止める
for(int i = 0; i < sx; i++){ //全てのセル領域に対して
for(int j = 0; j < sy; j++){
if(!cell[i][j]){//セルが空になっていれば
g.setColor(ColorOfVacantCell);
g.drawRect(i*z,j*z,RectSize,RectSize);
} else { //セルが生きていれば
g.setColor(ColorOfAliveCell);
g.drawRect(i*z,j*z,RectSize,RectSize);
}
}
}
wait = false; //スレッドの動作再開の許可
}
public void Life(){
int i, j, i2, i9, j2, j9;
byte counter;
boolean status = alive;
if(wait){return;} //ほかの処理を優先する
Graphics g = getGraphics();
for(i = 0; i < sx; i++){ //全てのセルに対して
for(j = 0; j < sy; j++){
if(!cell[i][j]){//セルが空で
if(oldcell[i][j]){//前は空でないなら書き直す
g.setColor(ColorOfVacantCell);
g.drawRect(i*z,j*z,RectSize,RectSize);
oldcell[i][j] = dead;
}
} else { //セルが生きていて
if(!oldcell[i][j]){//前は空だったら書き直す
g.setColor(Color.blue);//(セルの状況に変化がなければそのまま)
g.drawRect(i*z,j*z,RectSize,RectSize);
oldcell[i][j] = alive;
}
i2 = i-1; //周辺のセルに、このセルが
i9 = i+1; //生きているという情報を渡す
j2 = j-1;
j9 = j+1;
if(i2 < 0){i2 = sx-1;}
else if(i9 >= sx){i9 = 0;}
if(j2 < 0){j2 = sy-1;}
else if(j9 >= sy){j9 = 0;}
cellcounter[i2][j2]++;
cellcounter[i2][j]++;
cellcounter[i2][j9]++;
cellcounter[i][j2]++;
cellcounter[i][j9]++;
cellcounter[i9][j2]++;
cellcounter[i9][j]++;
cellcounter[i9][j9]++;
}
}
}
for(i = 0; i < sx; i++){ //全てのセルに対して
for(j = 0; j < sy; j++){
counter = cellcounter[i][j];//周辺のセルの数に応じて次世代の姿を決める
if(counter <= die){cell[i][j] = dead;}
else if(counter <= unchange){}
else if(counter <= reproduce){cell[i][j] = alive;}
else {cell[i][j] = dead;}
cellcounter[i][j] = 0; //セル情報のクリア
}
}
}
public boolean mouseDrag(Event evt, int x, int y){//マウスのドラッグ
return mouseDown(evt, x, y); //mouseDownと同じ動作
}
public boolean mouseDown(Event evt, int x, int y){//マウスの押下
int i = x/z, j = y/z; //マウスのセル単位での現在位置
if(!wait){return false;}
if((i < sx)&&(j < sy)&&(i > 0)&&(j > 0)){//セルの領域に入っていれば
Graphics g = getGraphics();//現在のスクリーンに
g.setColor(ColorOfAliveCell);
g.drawRect(i*z,j*z,RectSize,RectSize);//新しいセルを描く
cell[i][j] = oldcell[i][j] = !cell[i][j];//セルの設定
}
return true; //役には立たないが形だけ返す
}
public boolean action(Event e, Object arg) {
if (e.target instanceof Choice) {//リストから選択されたか?
if("low".equals(arg)){//"low"が選択されたか?
noudo = 0.15;//セルの初期分布濃度設定
init();
repaint();//初期化・実行
} else if("middle".equals(arg)){//"middle"が選択されたか?
noudo = 0.25;
init();
repaint();//初期化・実行
} else if("high".equals(arg)){//"high"が選択されたか?
noudo = 0.50;
init();
repaint();//初期化・実行
} else if("normal".equals(arg)){//普通のライフゲームの設定
die = 1; unchange = 2; reproduce = 3;
} else if("type 2".equals(arg)){
die = 1; unchange = 3; reproduce = 5;
} else if("type 3".equals(arg)){
die = 1; unchange = 4; reproduce = 7;
} else if("type 4".equals(arg)){
die = 3; unchange = 3; reproduce = 8;
}
} else if (e.target instanceof Button) {//ボタンが押されたか?
if ("run".equals(arg)) {//再初期化・再実行
init();//初期化・実行
repaint();//初期化・実行
} else if ("stop".equals(arg)){ //一時停止
wait = true;//実行状況のフラグ
} else if ("continue".equals(arg)){//動作再開
wait = false;
}
}
return true; //役には立たないが形だけ返す
}
} //LifeGame classの終わり