編寫一個五子棋代碼量不會很大,但這好歹也算是個項目,因此仍是須要花點時間的。看別人的代碼須要耐心,要看懂別人的代碼就更須要耐心了,做爲一個程序員也就是須要這樣的耐心。固然,在代碼裏我會盡可能的多加一些註釋來提升代碼的可讀性,惟一的要求就是要讀者們一步一步的跟着我來,順着個人思路一步一步的深刻,這樣才能最終達到我寫這篇博客和你看這篇博客的目的。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); } } } }
如今人人五子棋就完成了。
但,這仍是無比不夠的。首先很是重要的界面不夠美觀,悔棋,從新開始,判斷輸贏後就不能夠再下棋等等都尚未實現,留給讀者們本身擴展了。