//
//   ライフゲームエディタJava版第2回
//
//          2000/ 6/20 宍戸 輝光
//

import java.awt.*;
import java.awt.event.*;

class CLdat2 { // データクラス

	private byte lifes[][],blifes[][]; // セル配列
	private int width,height; // 大きさ保存用変数
	private int rules[]={-1,-1,0,1,-1,-1,-1,-1,-1};

	CLdat2(int w,int h) { // コンストラクタ

		width=w;
		height=h;

		// 指定された大きさでセル配列確保
		lifes=new byte[width][height];
		blifes=new byte[width][height];

	}

	public int getWidth() {

		return width;

	}

	public int getHeight() {

		return height;

	}

	public byte getLife(int x,int y) {

		return lifes[x][y];

	}

	public void setLife(int x,int y,byte val) {

		lifes[x][y]=val;

	}

	public void setRules(int rul[]) {

		rules=rul;

	}

	public int[] getRules() {

		return rules;

	}

	public void next() { // 1ステップ進める

		int i,j,k,l,n,x,y;

		for (i=0;i<height;i++) // 処理前のセル配列を保存
			for (j=0;j<width;j++)
				blifes[j][i]=lifes[j][i];

		for (i=0;i<height;i++) // 注目セルを中心とする3×3セルの生物数計算
			for (j=0;j<width;j++) {

				n=0; // 生物数カウンタクリア

				for (k=-1;k<2;k++) // 周辺の生物数合計
					for (l=-1;l<2;l++) {

						if (j+l==-1)
							x=width-1;
						else if (j+l==width)
							x=0;
						else
							x=j+l;

						if (i+k==-1)
							y=height-1;
						else if (i+k==width)
							y=0;
						else
							y=i+k;

						n+=blifes[x][y];

					}

				n-=blifes[j][i]; // 注目セル自身の分を引く

				if (rules[n]==-1) // ルールで生死判定
					lifes[j][i]=0;
				else if (rules[n]==1)
					lifes[j][i]=1;

			}

	}

}

class CLdisp2 extends Canvas implements MouseListener { // 表示パネルクラス

	private CLdat2 ldat;
	private Image img;
	private Graphics g_img;
	private int vr=5;
	private int lwid,lhei;

	CLdisp2(CLdat2 dat) {

		ldat=dat; // 描画対象のデータクラスを保存

		// データクラスの大きさ保存
		lwid=ldat.getWidth();
		lhei=ldat.getHeight();

		setSize(lwid*vr+2,lhei*vr+2);
		setBackground(Color.white);

		addMouseListener(this);

	}

	private void drawDat() { // 現在の状況を描画

		Color cl;

		for (int i=0;i<lhei;i++)
			for (int j=0;j<lwid;j++) {

				// 生物の有無で色を設定
				if (ldat.getLife(j,i)==0)
					cl=Color.black;
				else
					cl=Color.green;

				g_img.setColor(cl);

				// 設定した色で(j,i)を塗りつぶす
				g_img.fillRect(j*vr+1,i*vr+1,vr-1,vr-1);

			}

	}

	public void paint(Graphics g) {

		if (img==null) { // 最初の描画時にイメージ作成

			img=createImage(lwid*vr,lhei*vr);
			g_img=img.getGraphics();

			g_img.setColor(Color.blue);
			g_img.fillRect(0,0,lwid*vr,lhei*vr);

		}

		drawDat(); // 現在の状況をイメージに描画

		g.drawImage(img,1,1,this);

	}

	public void update(Graphics g) { // ちらつき防止のためオーバーライド

		paint(g);

	}

	public void mousePressed(MouseEvent e) {}

	public void mouseClicked(MouseEvent e) { // マウスクリック

		int x=(int)((e.getX()-1)/vr);
		int y=(int)((e.getY()-1)/vr);

		if (ldat.getLife(x,y)==0)
			ldat.setLife(x,y,(byte)1);
		else
			ldat.setLife(x,y,(byte)0);

		repaint();

	}

	public void mouseReleased(MouseEvent e) {}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}

}

class CRule2 extends Panel { // ルール設定パネル

	Checkbox rchk[][];
	CheckboxGroup rchkb[];
	Label lb[];

	CRule2() {

		int i,j;
		rchk=new Checkbox[3][9];
		rchkb=new CheckboxGroup[9];
		String str[]=new String[3];
		str[0]="O";
		str[1]="X";
		str[2]="-";
		lb=new Label[9];

		setBackground(new Color(160,192,192));
		setLayout(new GridLayout(9,4,1,2));

		for (i=0;i<9;i++) { // チェックボックス作成

			lb[i]=new Label(String.valueOf(i),Label.CENTER);
			add(lb[i]);

			rchkb[i]=new CheckboxGroup();

			for (j=0;j<3;j++) {

				rchk[j][i]=new Checkbox(str[j],false,rchkb[i]);

				add(rchk[j][i]);

			}

		}

	}

	public void getRules(int rules[]) {

		for (int i=0;i<9;i++)
			if (rchk[0][i].getState())
				rules[i]=1;
			else if (rchk[1][i].getState())
				rules[i]=-1;
			else
				rules[i]=0;

	}

	public void setRules(int rules[]) {

		for (int i=0;i<9;i++)
			if (rules[i]==1)
				rchk[0][i].setState(true);
			else if (rules[i]==-1)
				rchk[1][i].setState(true);
			else
				rchk[2][i].setState(true);

	}

}

class CLife2 extends Frame implements ActionListener {

	CLdat2 ldat;
	Panel pl;
	Button bt,btNext;
	CLdisp2 disp;
	CRule2 rl;

	CLife2() {

		setLayout(new BorderLayout());

		ldat=new CLdat2(64,64);
		disp=new CLdisp2(ldat);
		rl=new CRule2();

		bt=new Button("Close"); // ボタン生成
		bt.addActionListener(this); // ボタンのイベントリスナ設定
		btNext=new Button("Next");
		btNext.addActionListener(this);

		pl=new Panel(); // 部品配置用パネル生成
		pl.setBackground(new Color(160,144,192));
		pl.add(bt); // パネルにボタン配置
		pl.add(btNext);

		rl.setRules(ldat.getRules());

		add(disp,"Center");
		add(pl,"South"); // パネルをフレーム上に配置
		add(rl,"East");

	}

	public static void main(String args[]) {

		CLife2 app=new CLife2(); // アプリケーション生成

		app.pack();
		app.show();

		app.repaint();

	}

	public void actionPerformed(ActionEvent e) {

		if (e.getSource()==bt) { // ボタンクリックイベント

			dispose(); // アプリケーションフレーム破棄
			System.exit(0); // 終了

		}

		if (e.getSource()==btNext) {

			rl.getRules(ldat.getRules());

			ldat.next();
			disp.repaint();

		}

	}

}