/*サンプログラム[gomoku.java]*/

import java.awt.*;
import java.util.Random;

public class gomoku extends java.applet.Applet implements Runnable {

	Image banmen;
	Graphics dr_ban;
	Choice sente,gote,lan;
	Font f;
	FontMetrics fm;
	Panel pn,pn2,pn3;
	Label siro,kuro,mes;
	Button bt,bt2;
	Checkbox speed;

	int i,i2,i3,j,n,waku_x,waku_y,turn=1,lastX,lastY,r,mesn;

	int koma[][]=new int [16][16]; /* 石の配置情報 */
	int score[][]=new int [16][16];

	int kuhakux[]=new int [6];
	int kuhakuy[]=new int [6];
	int kohox[]=new int [256];
	int kohoy[]=new int [256];

	boolean game=false,cpu=false,flg_paint,cpu_turn=false,waku=false;
	boolean cpuVScpu,draw,stopped;

	String st[]=new String[7]; /*メッセージ文字列*/
	Color waku_color;

	Random rnd=new Random();
	Thread runner=null;

	public void start(){

		resize(420,400);

		banmen=createImage(256,256); /*部品作成*/
		dr_ban=banmen.getGraphics();
		sente=new Choice();
		gote=new Choice();
		lan=new Choice();
		pn=new Panel();
		pn2=new Panel();
		pn3=new Panel();
		siro=new Label();
		kuro=new Label();
		mes=new Label();
		bt=new Button();
		bt2=new Button();
		speed=new Checkbox("cpu wait",null,false);
		speed.setBackground(Color.orange);

		f=new Font("TimesRoman",Font.PLAIN,12); /*ラベル・選択メニューFont*/
		sente.setFont(f);
		gote.setFont(f);
		lan.setFont(f);
		siro.setFont(f);
		kuro.setFont(f);
		mes.setFont(f);

		sente.addItem("Human"); /*ラベル・選択メニューのテキスト定義*/
		sente.addItem("Computer");
		gote.addItem("Human");
		gote.addItem("Computer");
		gote.select(1);
		lan.addItem("Japanese");
		lan.addItem("English");
		kuro.setText("\u5148\u624b\uff08\u9ed2\uff09");
		kuro.setBackground(Color.orange);
		siro.setText("\u5f8c\u624b\uff08\u767d\uff09");
		siro.setBackground(Color.orange);

		st[0]="\u30b9\u30bf\u30fc\u30c8\u30dc\u30bf\u30f3\u3067\u958b\u59cb\u3067\u3059";
		st[1]="\u9ed2\u306e\u756a\u3067\u3059";
		st[2]="\u767d\u306e\u756a\u3067\u3059";
		st[3]="\u9ed2\u306e\u52dd\u3061\uff01\uff01";
		st[4]="\u767d\u306e\u52dd\u3061\uff01\uff01";
		st[5]="\u5f15\u304d\u5206\u3051\uff01\uff01";
		st[6]="\u66f4\u65b0\u3057\u3066\u304f\u3060\u3055\u3044";
		mes.setText(st[0]);
		mes.setBackground(Color.orange);
		mesn=0;

		f=new Font("TimesRoman",Font.BOLD,16); /*ボタンの文字*/
		bt.setFont(f);
		bt2.setFont(f);

		bt.setLabel("Start");
		bt2.setLabel("Stop");

		setBackground(Color.orange); /*アプレットの背景をオレンジにする*/
		sente.setBackground(Color.white);/*選択メニューの背景を白にする*/
		gote.setBackground(Color.white);
		lan.setBackground(Color.white);
		bt.setBackground(Color.lightGray);
		bt2.setBackground(Color.lightGray);

		this.setLayout((LayoutManager)null); /*部品を配置*/
		add(pn);
		add(pn2);
		add(pn3);

		pn.reshape(0,8,400,48);
		pn2.reshape(0,328,400,32);
		pn3.reshape(32,368,240,24);

		pn.setLayout(new FlowLayout(FlowLayout.CENTER,4,4));
		pn2.setLayout(new FlowLayout(FlowLayout.CENTER,16,3));
		pn3.setLayout(new FlowLayout());

		pn.add(kuro);
		pn.add(sente);
		pn.add(siro);
		pn.add(gote);

		pn2.add(bt);
		pn2.add(bt2);
		pn2.add(speed);
		pn2.add(lan);

		pn3.add(mes);

		bt2.enable(false);

		mesn=0;
		banmenClear();/*盤を描く*/

		stopped=false;

		if (runner==null){

			runner=new Thread(this);
			runner.start();

		}

	}

	public void stop() {

		mes.setText(st[6]); /* 終了メッセージ表示 */

		if (runner!=null) { /*終了時にスレッド破棄*/

			runner.stop();
			runner=null;

		}

	}

	public void banmenClear(){

		int i,j;

		dr_ban.setColor(Color.green); /*盤面イメージをクリア*/
		dr_ban.fillRect(0,0,256,256);

		dr_ban.setColor(Color.black);

		for (i=0;i<16;i++)   /*碁盤の目を描く*/
			dr_ban.drawLine(i*16+8,8,i*16+8,248);
		for (i=0;i<16;i++)
			dr_ban.drawLine(8,i*16+8,248,i*16+8);

	}

	public void ishi_haiti(int x,int y) { /*石を置く*/

		koma[x][y]=turn;
		lastX=x;
		lastY=y;

		if (turn==1){

			dr_ban.setColor(Color.black);
			dr_ban.fillOval(1+x*16,1+y*16,13,13);

		}

		if (turn==-1) {

			dr_ban.setColor(Color.white);
			dr_ban.fillOval(1+x*16,1+y*16,13,13);
			dr_ban.setColor(Color.gray);
			dr_ban.drawOval(1+x*16,1+y*16,13,13);
		}


	}

	public boolean mouseMove(Event evt,int x,int y){

		int xx,yy;

		if (x<20 || x>275 ||y<68 ||y>319) /*マウスカーソルは盤面の中か?*/
			return false;  /*外なら何もしないでリターン*/

		xx=(int)((x-20)/16);
		yy=(int)((y-68)/16);

		if (koma[xx][yy]==0 && game==true && !cpuVScpu) /*石を置ける状態か?*/
			waku_color=Color.blue; /*おける状態なら枠の色は青*/
		else
			waku_color=Color.red; /*そうでなければ赤*/

		waku_x=18+xx*16; /*枠を描くアプレットの座標*/
		waku_y=66+yy*16;

		waku=true; /*枠をアプレットに描く*/
		repaint();

		return true;

	}

	public boolean mouseDown(Event evt,int x,int y){

		int xx,yy;

		if (x<20 || x>276 ||y<68 ||y>320 ||!game) /*カーソルは盤面の中か?*/
			return false; /*外なら何もしないでリターン*/

		if (cpu_turn || !flg_paint || cpuVScpu) /*石を置けない状態ならリターン*/
			return false;

		xx=(int)((x-20)/16); /*マウスカーソルの位置を盤面の座標に変換*/
		yy=(int)((y-68)/16);

		if (koma[xx][yy]==0) { /*カーソルの位置に石がなければ*/

			ishi_haiti(xx,yy); /*石を置く*/

			lastX=xx;
			lastY=yy;

			hantei(turn); /*もし勝負がついたならゲーム終了*/

			turn=-turn;

			flg_paint=false; /*再描画フラグを設定*/
			repaint();

			if (cpu)
				cpu_turn=true;

		}

		return true;

	}

	public void run() { /*スレッド本体*/

		while (runner!=null) {

			if (cpu_turn && flg_paint && !stopped) {/*対コンピュータなら*/

				cpuTurn(); /*コンピュータが石を配置*/

				hantei(turn); /*もし勝負がついたならゲーム終了*/

				turn=-turn;

				repaint();
				cpu_turn=false; /*コンピュータの番終了*/

			}


			if (cpuVScpu && flg_paint &&!stopped) {

				cpuTurn();
				hantei(turn);

				flg_paint=false;
				repaint();

				turn=-turn;

			}
		}

	}

	public boolean action(Event evt,Object what) {

		int saki,ato;

		if (evt.target==bt){ /*スタートボタン*/

			if (game) /*現在ゲーム中なら無効*/
				return false;

			cpu=false;
			cpuVScpu=false;

			for (i=0;i<16;i++) /*石の配置情報をクリア*/
				for (j=0;j<16;j++)
					koma[j][i]=0;

			banmenClear();

			turn=1;

			saki=sente.getSelectedIndex();
			ato=gote.getSelectedIndex();

			if (saki==1 && ato==0){ /*コンピュータ先手*/

				cpu=true;

				j=Math.abs(rnd.nextInt()) % 3+7;
				i=Math.abs(rnd.nextInt()) % 3+7;

				ishi_haiti(j,i);
				turn=-1;

			}

			if (saki==0 && ato==1)
				cpu=true;

			game=true;
			cpu_turn=false;

			bt.enable(false);
			bt2.enable(true);
			sente.enable(false);
			gote.enable(false);

			if (saki==1 && ato==1) 
				cpuVScpu=true;

			repaint();

			return true;

		}

		if (evt.target==bt2){ /*クリアボタン*/

			game=false;
			cpuVScpu=false;
			turn=1;

			bt.enable(true);
			bt2.enable(false);
			sente.enable(true);
			gote.enable(true);

			mesn=0;

			repaint();

			return true;

		}

		if (evt.target==lan) { /* 表示言語選択メニュー */

			if (lan.getSelectedIndex()==0) { /* 日本語表示 */

				st[0]="\u30b9\u30bf\u30fc\u30c8\u30dc\u30bf\u30f3";
				st[0]=st[0]+"\u3067\u958b\u59cb\u3067\u3059";
				st[1]="\u9ed2\u306e\u756a\u3067\u3059";
				st[2]="\u767d\u306e\u756a\u3067\u3059";
				st[3]="\u9ed2\u306e\u52dd\u3061\uff01\uff01";
				st[4]="\u767d\u306e\u52dd\u3061\uff01\uff01";
				st[5]="\u5f15\u304d\u5206\u3051\uff01\uff01";
				st[6]="\u66f4\u65b0\u3057\u3066\u304f\u3060\u3055\u3044";

				kuro.setText("\u5148\u624b\uff08\u9ed2\uff09");
				siro.setText("\u5f8c\u624b\uff08\u767d\uff09");

			} else if (lan.getSelectedIndex()==1) { /* 英語表示 */

				st[0]="Push Start Button!!";
				st[1]="Black's Turn";
				st[2]="White's Turn";
				st[3]="Black Win!!";
				st[4]="White Win!!";
				st[5]="Draw!!";
				st[6]="Please Reload!!";

				kuro.setText("Black");
				siro.setText("White");

			}

			repaint();
			return true;

		}

		return false;

	}

	public void sikou(int isi) { /*コンピュータの思考(盤面評価)*/

		int n0,n1,aite;

		int kati=15000,hissi=1000,sanren=500,mittu=100,futatu=10; /*点数*/
		int kati2=12000,hissi2=500,sanren2=200,mittu2=80,futatu2=10;

		for (i=0;i<16;i++) { /* 横に走査 */

			for(i2=0;i2<12;i2++) {

				n1=0;
				n0=0;
				aite=0;

				for (j=i2;jmax)
					max=score[j][i];

		n=0;

		for (i=0;i<16;i++) /*最高点の手を選択*/
			for (j=0;j<16;j++)
				if (score[j][i]==max) {

					kohox[n]=j;
					kohoy[n]=i;
					n++;

				}

		if (n==0)
			return false;

		n=Math.abs(rnd.nextInt()) % n;

		ishi_haiti(kohox[n],kohoy[n]);/*最高点の中から1つを実行*/
		return true;

	}

	public void hantei(int v){ /*石が5つ並んでいるかの判定*/

		byte n1,n2,n3,n4;

		draw=true;

		for (i=0;i<16;i++) /* すべてのマスに石があれば引き分け */
			for (j=0;j<16;j++)
				if (koma[j][i]==0)
					draw=false;

		if (draw) /* 引き分けならゲーム終了 */
			game_end();

		for (i=0;i<16;i++){
			n1=0;
			for (j=0;j<15;j++){

				if (koma[j][i]==v && koma[j+1][i]==v){ /*横方向*/

					n1++;

					if (n1>=4)
						game_end();

				} else
					n1=0;

			}

		}

		for (i=0;i<16;i++){
			n2=0;
			n3=0;
			n4=0;
			for (j=0;j<15;j++){

				if (koma[i][j]==v && koma[i][j+1]==v){ /*縦方向*/

					n2++;

					if (n2>=4) 
						game_end();

				} else
					n2=0;

				if ((i+j)<15){ /*斜め右下方向*/
					if (koma[i+j][j]==v && koma[i+j+1][j+1]==v) {

						n3++;

						if (n3>=4) 
							game_end();


					} else
						n3=0;

					if (koma[j][i+j]==v && koma[j+1][i+j+1]==v) {

						n4++;
						if (n4>=4)
							game_end();

					} else
						n4=0;

				}
			}
		}

		for (i=15;i>3;i--) { /*斜め左下方向(横に走査)*/
			n3=0;
			for (j=0;j<15;j++)

				if ((i-j)>0 && j<15)
					if (koma[i-j][j]==v && koma[i-j-1][j+1]==v) {

						n3++;
						if (n3>=4)
							game_end();

					} else
						n3=0;
		}

		for (i=0;i<12;i++){ /*斜め左下方向(縦に走査)*/
			n4=0;
			for (j=15;j>0;j--)

				if ((15-j+i)<15 && j>0)
					if (koma[j][15-j+i]==v && koma[j-1][15-j+i+1]==v) {

						n4++;
						if (n4>=4)
							game_end();

					} else
						n4=0;
		}

	}

	public void game_end(){ /* ゲーム終了 */

		game=false;
		cpuVScpu=false;

		bt.enable(true);
		sente.enable(true);
		gote.enable(true);

		if (turn==1) /*どちらが勝ったのか?*/
			mesn=3;
		else
			mesn=4;

		if (draw)
			mesn=5;

		if (!draw){

			dr_ban.setColor(Color.red); /*勝負がついた場所(石)を赤く囲む*/
			dr_ban.fillRect(lastX*16,lastY*16,16,16);

			if (koma[lastX][lastY]==1)
				dr_ban.setColor(Color.black);

			if (koma[lastX][lastY]==-1)
				dr_ban.setColor(Color.white);

			dr_ban.fillOval(1+lastX*16,1+lastY*16,13,13);

		}

		bt2.enable(false);

		repaint();

	}

	public void paint(Graphics g){

		if (turn==1){ /*ターン表示*/

			g.setColor(Color.black);
			if (game==true)
				mesn=1;

		}

		else {
			g.setColor(Color.white);
			if (game==true)
				mesn=2;
		}

		if (!game)
			g.setColor(Color.orange);

		g.fillOval(280,64,24,24);
		mes.setText(st[mesn]); /*メッセージ表示*/

		g.drawImage(banmen,16,64,this); /*盤面イメージ表示*/

		if (waku){ /* 盤面上のカーソル枠を表示 */

			g.setColor(waku_color);
			g.drawRect(waku_x,waku_y,11,11);

		}

		flg_paint=true;

	}

	public void update(Graphics g){

		paint(g);

	}

}