單機版五子棋
這個小遊戲是我和我姐們兒的JAVA課程設計,也是我做的第一個JAVA項目,適合初學者,希望能幫到那些被JAVA課設所困擾的孩紙們~~~
一、該遊戲需要的實現的:
1、設計主架構,介面。
2、利用ActionListener介面實現按鈕事件的監聽。
3、重新開始功能的實現。
4、悔棋功能的實現。
5、退出功能的實現。
6、棋盤中棋子點類的定義。
7,利用MouseListener介面實現事件監聽,並實現介面裡的所有方法。
8,當滑鼠移動到棋盤上的交點上,且該點上無棋子時能夠變成小手形狀。
9,點擊棋盤時,利用if語句判斷該點是否點在交點上,並利用foreach語句和棋子類中的getX(),getY()方法遍曆每一個棋子的位置判斷該點是否有棋子。
10,當判斷到可以在所點擊的點上下子時,畫棋子時利用for迴圈遍曆已有的每一個點並利用Graphics類的setColor設定顏色,利用Graphics類的fillOval方法設定形狀大小。
11,當畫完棋子時要及時判斷輸贏,用棋子所在索引和for迴圈遍曆最後一個棋子的各個方向,如果有在同一條直線上的棋子個數大於等於五的即當前棋子所代表的那方贏。
12,勝負已定的時候,能夠彈出相應的資訊。
二、功能代碼實現
2.1進入遊戲
public static void main(String[] args) {StartChessJFrame f=new StartChessJFrame();//建立主架構f.setVisible(true);//顯示主架構}
2.2初始化,定義一些要用到的量。
private ChessBoard chessBoard;//對戰面板private Panel toolbar;//工具條面板private Button startButton;//設定開始按鈕private Button backButton;//設定悔棋按鈕private Button exitButton;//設定退出按鈕
2.3介面的構造方法(遊戲的架構)
public StartChessJFrame(){setTitle("單機版五子棋");//設定標題chessBoard=new ChessBoard();//初始化面板對象,建立和添加菜單MyItemListener lis=new MyItemListener();//初始化按鈕事件監聽器內部類toolbar=new Panel();//工具面板欄執行個體化startButton=new Button("重新開始");backButton=new Button("悔棋");exitButton=new Button("退出");//三個按鈕初始化toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));//將工具面板按鈕用FlowLayout布局toolbar.add(backButton);toolbar.add(startButton);toolbar.add(exitButton);//將三個按鈕添加到工具面板上startButton.addActionListener(lis);backButton.addActionListener(lis);exitButton.addActionListener(lis);//將三個按鈕事件註冊監聽事件add(toolbar,BorderLayout.SOUTH);//將工具面板布局到介面南方也就是下面add(chessBoard);//將面板對象添加到表單上setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設定介面關閉事件pack();//自適應大小}
2.4按鈕的實現與監聽(構造方法內部)
MyItemListener lis=new MyItemListener();//初始化按鈕事件監聽器內部類toolbar=new Panel();//工具面板欄執行個體化startButton=new Button("重新開始");backButton=new Button("悔棋");exitButton=new Button("退出");//三個按鈕初始化toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));//將工具面板按鈕用FlowLayout布局toolbar.add(backButton);toolbar.add(startButton);toolbar.add(exitButton);//將三個按鈕添加到工具面板上startButton.addActionListener(lis);backButton.addActionListener(lis);exitButton.addActionListener(lis);//將三個按鈕事件註冊監聽事件
2.5按鈕事件的監聽
private class MyItemListener implements ActionListener{public void actionPerformed(ActionEvent e) {Object obj=e.getSource();//擷取事件來源if(obj==startButton){System.out.println("重新開始...");//重新開始//JFiveFrame.this內部類引用外部類chessBoard.restartGame();}else if(obj==exitButton){System.exit(0);//結束應用程式}else if(obj==backButton){System.out.println("悔棋...");//悔棋chessBoard.goback();}}}
2.6重新開始按鈕的功能實現
public void restartGame(){//清除棋子for(int i=0;i<chessList.length;i++)chessList[i]=null;/*恢複遊戲相關的變數值*/isBack=true;gameOver=false;//遊戲是否結束chessCount=0;//當前棋盤的棋子個數repaint();}
2.7悔棋按鈕的功能實現
public void goback(){if(chessCount==0)return ;chessList[chessCount-1]=null;chessCount--;if(chessCount>0){xIndex=chessList[chessCount-1].getX();yIndex=chessList[chessCount-1].getY();}isBack=!isBack;repaint();}
2.8當棋盤根據需要變大或變小時視窗應隨之發生改變
//Dimension:矩形ChessBoard類內部public Dimension getPreferredSize(){return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2+GRID_SPAN*ROWS);}pack();//自適應大小StartChessBoard類內部
2.9定義棋子類
import java.awt.*;public class Point {private int x;//棋子在棋盤中的x索引值private int y;//棋子在棋盤中的y索引值private Color color;//顏色public static int DIAMETER=30;//直徑public Point(int x,int y,Color color){this.x=x;this.y=y;this.color=color;}//得到棋子在棋盤中的x索引值public int getX(){return x;}//得到棋子在棋盤中的y索引值public int getY(){return y;}//得到棋子顏色public Color getColor(){return color;}}
三、功能部分代碼實現
3.1初始化,定義一些要用到的量。
public static int MARGIN=30;//邊距public static int GRID_SPAN=35;//網格間距public static int ROWS=18;//棋盤行數public static int COLS=18;//棋盤列數Point[] chessList=new Point[(ROWS+1)*(COLS+1)];//初始化每個數組元素為nullboolean isBack=true;//預設開始是黑棋先下boolean gameOver=false;//遊戲是否結束int chessCount;//當前棋盤的棋子個數int xIndex,yIndex;//當前剛下棋子的索引
3.2棋盤對象的構造方法
public ChessBoard(){setBackground(Color.LIGHT_GRAY);//設定背景顏色為灰色addMouseListener(this);//添加事件監聽器addMouseMotionListener(new MouseMotionListener() {//匿名內部類@Overridepublic void mouseMoved(MouseEvent e) {int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;//將按一下滑鼠的座標位置轉化為網格索引if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1)){//遊戲已經結束,不能下;落在棋盤外,不能下;x,y位置已經有棋子存在,不能下setCursor(new Cursor(Cursor.DEFAULT_CURSOR));//設定成預設圖案}else{setCursor(new Cursor(Cursor.HAND_CURSOR));//設定成手型}}@Overridepublic void mouseDragged(MouseEvent e) {}});}
3.3設定滑鼠監聽器,變小手(在構造方法內部)
addMouseMotionListener(new MouseMotionListener() {//匿名內部類@Overridepublic void mouseMoved(MouseEvent e) {int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;//將按一下滑鼠的座標位置轉化為網格索引if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1)){//遊戲已經結束,不能下;落在棋盤外,不能下;x,y位置已經有棋子存在,不能下setCursor(new Cursor(Cursor.DEFAULT_CURSOR));//設定成預設圖案}else{setCursor(new Cursor(Cursor.HAND_CURSOR));//設定成手型}}@Overridepublic void mouseDragged(MouseEvent e) {}});
3.4點擊棋盤時的滑鼠按壓事件
public void mousePressed(MouseEvent e) {//滑鼠按鍵在組件上按下時調用if(gameOver)//遊戲已經結束,不能下return ;String colorName=isBack ? "黑棋" : "白棋";xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;//將按一下滑鼠的座標位置轉化為網格索引if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS)//棋子落在棋盤外,不能下return ;if(findChess(xIndex,yIndex))//x,y位置已經有棋子存在,不能下return ;Point ch=new Point(xIndex,yIndex,isBack ? Color.black : Color.white);chessList[chessCount++]=ch;repaint();//通知系統重新繪製if(isWin()){String msg=String.format("恭喜,%s贏啦~", colorName);JOptionPane.showMessageDialog(this, msg);gameOver=true;}else if(chessCount==(COLS+1)*(ROWS+1)){String msg=String.format("棋鼓相當,棒棒噠~");JOptionPane.showMessageDialog(this,msg);gameOver=true;}isBack=!isBack;}
3.5繪製棋盤,棋子還有紅框框
public void paintComponent(Graphics g){super.paintComponent(g);//畫棋盤for(int i=0;i<=ROWS;i++){//畫橫線g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);}for(int i=0;i<=COLS;i++){//畫直線g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN,MARGIN+ROWS*GRID_SPAN);}/*畫棋子*/for(int i=0;i<chessCount;i++){int xPos=chessList[i].getX()*GRID_SPAN+MARGIN;//網格交叉的x座標int yPos=chessList[i].getY()*GRID_SPAN+MARGIN;//網格交叉的y座標g.setColor(chessList[i].getColor());//設定顏色g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);if(i==chessCount-1){g.setColor(Color.red);//標記最後一個棋子為紅色 g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);}}}
3.6判斷輸贏
/*判斷哪方贏*/private boolean isWin(){int continueCount=1;//連續棋子的個數for(int x=xIndex-1;x>=0;x--){//橫向向左尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,yIndex,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex+1;x<=ROWS;x++){//橫向向右尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,yIndex,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int y=yIndex-1;y>=0;y--){//縱向向上尋找Color c=isBack ? Color.black : Color.white;if(getChess(xIndex,y,c)!=null){continueCount++;}elsebreak;}for(int y=yIndex+1;y<=ROWS;y++){//縱向向下尋找Color c=isBack ? Color.black : Color.white;if(getChess(xIndex,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){//右下尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex-1,y=yIndex+1;y<=ROWS&&x>=0;x--,y++){//左上尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int x=xIndex-1,y=yIndex-1;y>=0&&x>=0;x--,y--){//左下尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex+1,y=yIndex+1;y<=ROWS&&x<=COLS;x++,y++){//右上尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;return false;}
3.7彈出相應訊息框(在滑鼠按壓函數內部)
if(isWin()){String msg=String.format("恭喜,%s贏啦~", colorName);JOptionPane.showMessageDialog(this, msg);gameOver=true;}else if(chessCount==(COLS+1)*(ROWS+1))//平局{String msg=String.format("棋鼓相當,棒棒噠~");JOptionPane.showMessageDialog(this,msg);gameOver=true;}
3.8上面用到的一個判斷某點是否有棋子的函數
private boolean findChess(int x,int y){for(Point c:chessList){if(c!=null&&c.getX()==x&&c.getY()==y)return true;}return false;}
3.9因為該棋盤類實現了滑鼠監聽介面MonseListener,所以要重寫該介面內的所有方法,其它方法如下
@Overridepublic void mouseClicked(MouseEvent e) {//滑鼠按鍵在組件上單擊(按下並釋放)時調用}@Overridepublic void mouseReleased(MouseEvent e) {////滑鼠按鍵在組件上釋放時調用}@Overridepublic void mouseEntered(MouseEvent e) {//滑鼠進入組件時調用}@Overridepublic void mouseExited(MouseEvent e){//滑鼠離開組件時調用}
四、運行結果
五、代碼匯總
該遊戲總共建了三個類,一個是介面StartChessJFrame,一個是棋盤類ChessBoard,一個是棋子類Point
5.1StartChessJFrame類
package chess.lcc.com;import javax.swing.*;import java.awt.event.*;import java.awt.*;/* * 五子棋的主架構,程式啟動類 */public class StartChessJFrame extends JFrame {private ChessBoard chessBoard;//對戰面板private Panel toolbar;//工具條面板private Button startButton;//設定開始按鈕private Button backButton;//設定悔棋按鈕private Button exitButton;//設定退出按鈕public StartChessJFrame(){setTitle("單機版五子棋");//設定標題chessBoard=new ChessBoard();//初始化面板對象,建立和添加菜單MyItemListener lis=new MyItemListener();//初始化按鈕事件監聽器內部類toolbar=new Panel();//工具面板欄執行個體化startButton=new Button("重新開始");backButton=new Button("悔棋");exitButton=new Button("退出");//三個按鈕初始化toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));//將工具面板按鈕用FlowLayout布局toolbar.add(backButton);toolbar.add(startButton);toolbar.add(exitButton);//將三個按鈕添加到工具面板上startButton.addActionListener(lis);backButton.addActionListener(lis);exitButton.addActionListener(lis);//將三個按鈕事件註冊監聽事件add(toolbar,BorderLayout.SOUTH);//將工具面板布局到介面南方也就是下面add(chessBoard);//將面板對象添加到表單上setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設定介面關閉事件pack();//自適應大小}private class MyItemListener implements ActionListener{public void actionPerformed(ActionEvent e) {Object obj=e.getSource();//擷取事件來源if(obj==startButton){System.out.println("重新開始...");//重新開始//JFiveFrame.this內部類引用外部類chessBoard.restartGame();}else if(obj==exitButton){System.exit(0);//結束應用程式}else if(obj==backButton){System.out.println("悔棋...");//悔棋chessBoard.goback();}}}public static void main(String[] args) {StartChessJFrame f=new StartChessJFrame();//建立主架構f.setVisible(true);//顯示主架構}}5.2ChessBoard類
package chess.lcc.com;import javax.swing.*;import java.awt.*;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import java.awt.event.MouseEvent;/*五子棋-棋盤類*/public class ChessBoard extends JPanel implements MouseListener{public static int MARGIN=30;//邊距public static int GRID_SPAN=35;//網格間距public static int ROWS=15;//棋盤行數public static int COLS=15;//棋盤列數Point[] chessList=new Point[(ROWS+1)*(COLS+1)];//初始化每個數組元素為nullboolean isBack=true;//預設開始是黑棋先下boolean gameOver=false;//遊戲是否結束int chessCount;//當前棋盤的棋子個數int xIndex,yIndex;//當前剛下棋子的索引public ChessBoard(){setBackground(Color.LIGHT_GRAY);//設定背景顏色為黃色addMouseListener(this);//添加事件監聽器addMouseMotionListener(new MouseMotionListener() {//匿名內部類@Overridepublic void mouseMoved(MouseEvent e) {int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;//將按一下滑鼠的座標位置轉化為網格索引if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1)){//遊戲已經結束,不能下;落在棋盤外,不能下;x,y位置已經有棋子存在,不能下setCursor(new Cursor(Cursor.DEFAULT_CURSOR));//設定成預設圖案}else{setCursor(new Cursor(Cursor.HAND_CURSOR));//設定成手型}}@Overridepublic void mouseDragged(MouseEvent e) {}});}/*繪製*/public void paintComponent(Graphics g){super.paintComponent(g);//畫棋盤for(int i=0;i<=ROWS;i++){//畫橫線g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);}for(int i=0;i<=COLS;i++){//畫直線g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN,MARGIN+ROWS*GRID_SPAN);}/*畫棋子*/for(int i=0;i<chessCount;i++){int xPos=chessList[i].getX()*GRID_SPAN+MARGIN;//網格交叉的x座標int yPos=chessList[i].getY()*GRID_SPAN+MARGIN;//網格交叉的y座標g.setColor(chessList[i].getColor());//設定顏色g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);if(i==chessCount-1){g.setColor(Color.red);//標記最後一個棋子為紅色 g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);}}}@Overridepublic void mousePressed(MouseEvent e) {//滑鼠按鍵在組件上按下時調用if(gameOver)//遊戲已經結束,不能下return ;String colorName=isBack ? "黑棋" : "白棋";xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;//將按一下滑鼠的座標位置轉化為網格索引if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS)//棋子落在棋盤外,不能下return ;if(findChess(xIndex,yIndex))//x,y位置已經有棋子存在,不能下return ;Point ch=new Point(xIndex,yIndex,isBack ? Color.black : Color.white);chessList[chessCount++]=ch;repaint();//通知系統重新繪製if(isWin()){String msg=String.format("恭喜,%s贏啦~", colorName);JOptionPane.showMessageDialog(this, msg);gameOver=true;}else if(chessCount==(COLS+1)*(ROWS+1)){String msg=String.format("棋鼓相當,棒棒噠~");JOptionPane.showMessageDialog(this,msg);gameOver=true;}isBack=!isBack;}@Overridepublic void mouseClicked(MouseEvent e) {//滑鼠按鍵在組件上單擊(按下並釋放)時調用}@Overridepublic void mouseReleased(MouseEvent e) {////滑鼠按鍵在組件上釋放時調用}@Overridepublic void mouseEntered(MouseEvent e) {//滑鼠進入組件時調用}@Overridepublic void mouseExited(MouseEvent e){//滑鼠離開組件時調用}private boolean findChess(int x,int y){for(Point c:chessList){if(c!=null&&c.getX()==x&&c.getY()==y)return true;}return false;}/*判斷那方贏*/private boolean isWin(){int continueCount=1;//連續棋子的個數for(int x=xIndex-1;x>=0;x--){//橫向向左尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,yIndex,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex+1;x<=ROWS;x++){//橫向向右尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,yIndex,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int y=yIndex-1;y>=0;y--){//縱向向上尋找Color c=isBack ? Color.black : Color.white;if(getChess(xIndex,y,c)!=null){continueCount++;}elsebreak;}for(int y=yIndex+1;y<=ROWS;y++){//縱向向下尋找Color c=isBack ? Color.black : Color.white;if(getChess(xIndex,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){//右下尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex-1,y=yIndex+1;y<=ROWS&&x>=0;x--,y++){//左上尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;//for(int x=xIndex-1,y=yIndex-1;y>=0&&x>=0;x--,y--){//左下尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}for(int x=xIndex+1,y=yIndex+1;y<=ROWS&&x<=COLS;x++,y++){//右上尋找Color c=isBack ? Color.black : Color.white;if(getChess(x,y,c)!=null){continueCount++;}elsebreak;}if(continueCount>=5){//判斷記錄數大於等於五,即表示此方獲勝return true;}elsecontinueCount=1;return false;}private Point getChess(int xIndex,int yIndex,Color color){for(Point c:chessList){if(c!=null&&c.getX()==xIndex&&c.getY()==yIndex&&c.getColor()==color)return c;}return null;}public void restartGame(){//清除棋子for(int i=0;i<chessList.length;i++)chessList[i]=null;/*恢複遊戲相關的變數值*/isBack=true;gameOver=false;//遊戲是否結束chessCount=0;//當前棋盤的棋子個數repaint();}public void goback(){if(chessCount==0)return ;chessList[chessCount-1]=null;chessCount--;if(chessCount>0){xIndex=chessList[chessCount-1].getX();yIndex=chessList[chessCount-1].getY();}isBack=!isBack;repaint();}//Dimension:矩形public Dimension getPreferredSize(){return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2+GRID_SPAN*ROWS);}}
5.3Point類
package chess.lcc.com;import java.awt.*;public class Point {private int x;//棋子在棋盤中的x索引值private int y;//棋子在棋盤中的y索引值private Color color;//顏色public static int DIAMETER=30;//直徑public Point(int x,int y,Color color){this.x=x;this.y=y;this.color=color;}//得到棋子在棋盤中的x索引值public int getX(){return x;}//得到棋子在棋盤中的y索引值public int getY(){return y;}//得到棋子顏色public Color getColor(){return color;}}