五子棋之人人五子棋

     編寫一個五子棋代碼量不會很大,但這好歹也算是個項目,因此仍是須要花點時間的。看別人的代碼須要耐心,要看懂別人的代碼就更須要耐心了,做爲一個程序員也就是須要這樣的耐心。固然,在代碼裏我會盡可能的多加一些註釋來提升代碼的可讀性,惟一的要求就是要讀者們一步一步的跟着我來,順着個人思路一步一步的深刻,這樣才能最終達到我寫這篇博客和你看這篇博客的目的。java

        那下面呢,我就具體介紹一下人人五子棋是如何實現的。程序員

   1)首先咱們要有一個五子棋界面,就是畫出許多行橫線和許多行豎線算法

 

private void DrawCheesTable(Graphics g) {
		// TODO Auto-generated method stub
		//畫出指定的行數
		for( int i = 0; i < Config.ROWS; i++)
			g.drawLine(Config.X0, Config.Y0 + Config.SIZE * i,
					Config.X0 + Config.SIZE *( Config.COLUMNS - 1), Config.Y0 +Config.SIZE * i);
		//畫出指定的列數
		for( int i = 0; i < Config.COLUMNS; i++)
			g.drawLine(Config.X0 + Config.SIZE * i,Config.Y0, 
					Config.X0 + Config.SIZE * i,Config.Y0 +( Config.ROWS - 1) * Config.SIZE);
	}

 

     看到上面的代碼裏面有一些奇怪的符號吧,不急,那是我事先定義好的保存常量數據的類。另外,for語句中畫線所用到的數據是如何給定的,留給讀者本身分析了。數組

    2)建立一個保存常量的類,爲了方便咱們改變棋子大小,棋盤大小 函數

      棋盤畫好了,如今就來實現釋放鼠標時畫填充圓。鼠標釋放,就用到 public void mouseReleased(MouseEvent e) {}函數,因而就要監聽器類extends java.awt.event.MouseAdapter了。this

public interface Config {
	//棋盤的初始點座標
	public static final int X0 = 50;
	public static final int Y0 = 50;	
	//多少列多少行
	public static final int ROWS = 11;
	public static final int COLUMNS = 14;
	//棋子的大小  
	//格子的大小
	public static final int CHESS_SIZE = 40;
	public static final int SIZE = 40;
	
}

 

    3)鼠標釋放方法spa

public void mouseReleased(MouseEvent e) {
		
		//獲得鼠標釋放時的點的座標
		int x1 = e.getX();
		int y1 = e.getY();
		//按下點後咱們就去找 它在拿個交點附近
		for(int i = 0; i < Config.ROWS; i++){
			for(int j = 0; j < Config.COLUMNS; j++){
				//獲得每個交點的值
				xx = Config.X0 + Config.SIZE * j;
				yy = Config.Y0 + Config.SIZE * i;
				//若是這個交點能夠放棋子
				if(FiveChress_array[i][j] == 0)
					//判斷離誰更近
					if(x1 > xx - Config.SIZE/3 && x1 < xx + Config.SIZE/ 3 && y1 > yy - Config.SIZE /3 && y1 < yy + Config.SIZE /3 )
						//花黑棋
						if(count){
							System.out.println("再黑棋中xx的值是 " +xx +"\t" + "在黑棋中yy的值是  " + yy);
							//畫出來的是黑棋
							g.setColor(java.awt.Color.BLACK);
							g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);
							//下一次是畫白棋
							count = false;
							//用數組記錄每一個交點的屬性 1黑棋 0空白 -1白棋
							FiveChress_array[i][j] = 1;
							x = j;
							y = i;
							//畫出了點酒結束 再也不循環
							break;
						}else{
							//畫白棋		
							System.out.println("再白棋中xx的值是 " +xx +"\t" + "在白棋中yy的值是  " + yy);
							g.setColor(java.awt.Color.WHITE);
							g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);
							count = true;
							FiveChress_array[i][j] = -1 ;
							x = j;
							y = i;
							//畫出了點酒結束 再也不循環
							break;
						}					
			}

		}
		//調用判斷是否贏棋函數
		win_or_not(x,y);
	}

      這其中包含了一個判斷鼠標按下點離哪一個棋盤交點最近的算法,留給讀者本身分析了。裏面同時有使用不少的變量它們的聲明以下code

//定義畫板對象 
	private java.awt.Graphics g;
	//每一個棋子的基本屬性    true表示要放黑棋  false表示要放白棋 
	private boolean count = true;
	//再建立兩個數來表示交點座標 使得畫出來的圈圓心會在交點
	private int xx,yy;
	//建立(x,y)來表示按下的那個點所放在的焦點座標  好比(1,3) 表示第一行第三個交點
	private int x,y;
	//建立一個數組記錄每一個能夠放棋子的點的狀態  0表示空  1表示黑棋 -1表示白棋
	private int [][] FiveChress_array = new int[Config.ROWS][Config.COLUMNS];

     4)鼠標監聽器類的構造函數對象

//構造函數
	public ChessListener(java.awt.Graphics g1 , int [][] FiveChress_array){
		//地址傳遞
		this.g = g1;
		this.FiveChress_array = FiveChress_array;
	}

     如今咱們的棋子能夠下了,並且能夠下在正確的位置上,下面要作的是實現win_or_not()函數了,該函數裏咱們要實現行列左傾斜,右傾斜的判斷。blog

      5)實現win_or_not()函數

private void win_or_not(int x, int y) {
		//若是在行列左斜右斜的方向上有了五個連續的同色棋子 就能夠判斷出輸贏了
		System.out.println("進入win_or_not函數");
		if(check_row(x,y) || check_columns(x,y) || check_left(x,y) || check_right(x,y) ){
			if(!count){
				//黑棋贏了
				JOptionPane.showMessageDialog(null,"我靠 黑棋贏了");				
				System.out.println("我靠 黑棋贏了");
			}else{
				//白棋贏了
				JOptionPane.showMessageDialog(null,"我靠 白棋贏了");
				System.out.println("我靠 白棋贏了");
			}
		}
	}

     在if判斷裏調用了判斷行、列、左斜、右斜的函數。其中JOptionPane.showMessageDialog(null,"");是用來彈出一個對話框突出顯示輸贏。

     6)check_row函數的實現

private boolean check_row(int x, int y) {
		int num = 0; //表示相同顏色的棋子個數
		//開始向右找相鄰的相同顏色的
		for(int i = x ; i < Config.COLUMNS ; i++){
			if(FiveChress_array[y][x] == FiveChress_array[y][i]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//開始向左找相鄰的相同顏色的
		for(int i = x ; i > 0 ; i--){
			if(FiveChress_array[y][x] == FiveChress_array[y][i-1]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		System.out.println("在check_row函數裏num = " + num);

		//若是有了五個或五個以上的連續相同顏色就給出判斷 true
		if(num >= 5)
			return true;
		else
			return false;
	}

 

     7)check_columns函數的實現

private boolean check_columns(int x, int y) {
		int num = 0; //表示相同顏色的棋子個數
		//開始向右找相鄰的相同顏色的
		for(int i = y ; i < Config.ROWS ; i++){
			if(FiveChress_array[y][x] == FiveChress_array[i][x]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//開始向左找相鄰的相同顏色的
		for(int i = y ; i > 0 ; i--){
			if(FiveChress_array[y][x] == FiveChress_array[i-1][x]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		System.out.println("在check_columns函數中num = " + num);

		//若是有了五個或五個以上的連續相同顏色就給出判斷 true
		if(num >= 5)
			return true;
		else
			return false;
	}

 

     8)check_left函數的實現

private boolean check_left(int x, int y) {
		int num = 0; //表示相同顏色的棋子個數
		//定義ix,jy記錄下(y,x);
		int ix = x;
		int jy = y;
		//開始向右上找相鄰的相同顏色的
		for(int i = x, j = y;(Config.COLUMNS - i) < j ? (i < Config.COLUMNS) : j >= 0 ; i++,j--){
			if(FiveChress_array[y][x] == FiveChress_array[j][i]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//開始向左下角找相鄰的相同顏色的
		for(int i = ix, j = jy ; i <(Config.ROWS - j) ? i>=0 : (j < Config.ROWS) ; i--,j++){
			if(FiveChress_array[jy][ix] == FiveChress_array[j][i]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//在兩個for循環裏有兩次和本身比較顏色
		num--;
		System.out.println("在check_left函數裏num = " + num);

		//若是有了五個或五個以上的連續相同顏色就給出判斷 true
		if(num >= 5)
			return true;
		else
			return false;
	}

 

     9)check_right函數的實現

private boolean check_right(int x, int y) {
		int num = 0; //表示相同顏色的棋子個數
		//定義i,j記錄下(y,x);
		int ix = x;
		int jy = y;
		//開始向右下角找相鄰的相同顏色的
		for(int i = x, j = y;(Config.COLUMNS - i) < (Config.ROWS - j) ? (i < Config.COLUMNS) : (j < Config.ROWS) ; i++,j++){
			if(FiveChress_array[jy][ix] == FiveChress_array[j][i]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//開始向左上角找相鄰的相同顏色的
		for(int i = ix, j = jy ; i < j ? i >= 0 : j >= 0 ; i--,j--){
			if(FiveChress_array[y][x] == FiveChress_array[j][i]){
				//找到了 就加一
				num ++;
			}else{
				//找到了有一個不是 就跳出
				break;
			}				
		}
		//在兩個for循環裏有兩次和本身比較顏色
		num--;
		System.out.println("在check_right函數裏num = " + num);

		//若是有了五個或五個以上的連續相同顏色就給出判斷 true
		if(num >= 5)
			return true;
		else
			return false;
		}

    這些個方法都大同小異,主要注意它們的座標,和遞增遞減關係,行和列必定不能表示錯。x的改變就是列數的改變,y的改變就是行數的改變。

    寫到這裏基本上人人五子棋就完成了,下面要作的就是重繪,由於以前咱們已經有用一個二維數組及路線每個交點的屬性,如今這個也就比較好實現了。

    10)paint函數的重寫

public void paint(Graphics g1){
		//先繪出各個組件
		super.paint(g1);
		//繪出棋盤
		DrawCheesTable(g1);
		//重繪棋子
		DrawChees(g1);
		
	}

    11)重繪棋子函數的實現

private void DrawChees(Graphics g1) {
		// TODO Auto-generated method stub
		for(int i = 0; i < Config.ROWS; i++){
			for(int j = 0; j < Config.COLUMNS; j++){
				//獲得每個交點的值
				xx = Config.X0 + Config.SIZE * j;
				yy = Config.Y0 + Config.SIZE * i;
				if(FiveChress_array[i][j] == 1){
					g.setColor(Color.BLACK);
					g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);
				}else if(FiveChress_array[i][j] == -1){
					g.setColor(Color.WHITE);
					g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);
				}		
				
			}
		}

	}

     如今人人五子棋就完成了。

     但,這仍是無比不夠的。首先很是重要的界面不夠美觀,悔棋,從新開始,判斷輸贏後就不能夠再下棋等等都尚未實現,留給讀者們本身擴展了。