實現一個Java五子棋

五子棋手把手教你寫:

寫在前面的話:

回想起從前初學代碼的五子棋簡直寫的不像樣子。今天閒來無事就寫了個五子棋的小程序。前端

一來呢回憶一下好久之前寫代碼時的感受。java

二來呢順便幫下諸位有需求的學生,順利的Ctrl+C。git

五子棋的運行效果以下。算法

 

開發環境:

這個小程序是基於Java實現的。所以呢須要提早安裝JDK環境。(老油條忽略此條信息)數據庫

開發環境jdk1.8 + eclipse小程序

eclipse 目錄結構以下所示api

 

 

棋盤數據結構核心:

不管你作數據庫開發仍是作一些小程序,第一時間考慮的必須是需求+建模。把核心設計出來。數組

這次咱們用一個二維數組做爲棋盤,每條線交叉的地方設爲二維數組的值,並約定:數據結構

0=空eclipse

1=白棋

2=黑棋

而後對應的把下棋,悔棋,判斷輸贏(橫豎斜)和清盤的算法都實現出來。

具體展示以下:

悔棋時候咱們須要用一個棧來保存咱們以前下棋的信息:

/**
     * 在該位置下棋  1:white 2:black 
     * @param x 橫座標
     * @param y 縱座標
     * @param var 棋子種類
     * @return 1:white 贏   2:black贏
     */
    public int ChessIt(int x,int y,int var) {
        if(__CanInput(x,y)) {
            core[x][y] =var;
            Chess chess = new Chess(x,y);
            stack.push(chess);
            return checkVictory(x, y, var);
        }
        else return -1;
    }

//悔棋
    public boolean RetChess() {
        if(stack.isEmpty()) return false;
        Chess chess = stack.pop();
        core[chess.x][chess.y]= 0;
        return true;
    }

 

判斷輸贏:

private int checkVictory(int x,int y,int var) {
        //橫向判斷
        int trans = 0;
        for(int i=x-4;i<x+5;i++) {
            if(i<0||i>=this.x) continue;
            if(core[i][y]==var) {
                trans++;
            }
            else {
                trans=0;
            }
            if(trans==5) return var;
        }
        //縱向判斷
        int longitudinal = 0;
        for(int i=y-4;i<y+5;i++) {
            if(i<0||i>=this.y) continue;
            if(core[x][i]==var) {
                longitudinal++;
            }
            else {
                longitudinal=0;
            }
            if(longitudinal==5) return var;
        }
        //從左上到右下
        int leftUPToDown = 0;
        for(int i=x-4,j=y+4;i<x+5&&j>y-5;i++,j--) {
            if(i<0||i>=this.x||j<0||j>=this.y) continue;
            if(core[i][j]==var) {
                leftUPToDown++;
            }else {
                leftUPToDown=0;
            }
            if(leftUPToDown==5) return var;
        }
        //從左下到右上
        int leftDownToUP = 0;
        for(int i=x+4,j=y+4;i>x-5&&j>y-5;i--,j--) {
            if(i<0||i>=this.x||j<0||j>=this.y) continue;
            if(core[i][j]==var) {
                leftDownToUP++;
            }else {
                leftDownToUP=0;
            }
            if(leftDownToUP==5) return var;
        }
        return 0;
    }

 

整體:Core.java 的代碼以下·:

 

package main;

import java.util.Stack;

/**
 * @author GodofOrange
 *    棋盤數據結構
 */
public class Core {
    //棋盤大小
    private int[][] core;
    private int x;
    private int y;
    //記錄下棋的類
    class Chess{
        int x;
        int y;
        public Chess(int x,int y) {
            this.x=x;
            this.y=y;
        }
    }
    //
    Stack<Chess> stack;
    //構造方法
    public Core(int x,int y) {
        stack = new Stack<>();
        core = new int[x][y];
        this.x=x;
        this.y=y;
    }
    //檢查該地是否有空位置
    private boolean __CanInput(int x,int y) {
        if(core[x][y]==0) return true;
        else return false;
    }
    //判斷輸贏
    private int checkVictory(int x,int y,int var) {
        //橫向判斷
        int trans = 0;
        for(int i=x-4;i<x+5;i++) {
            if(i<0||i>=this.x) continue;
            if(core[i][y]==var) {
                trans++;
            }
            else {
                trans=0;
            }
            if(trans==5) return var;
        }
        //縱向判斷
        int longitudinal = 0;
        for(int i=y-4;i<y+5;i++) {
            if(i<0||i>=this.y) continue;
            if(core[x][i]==var) {
                longitudinal++;
            }
            else {
                longitudinal=0;
            }
            if(longitudinal==5) return var;
        }
        //從左上到右下
        int leftUPToDown = 0;
        for(int i=x-4,j=y+4;i<x+5&&j>y-5;i++,j--) {
            if(i<0||i>=this.x||j<0||j>=this.y) continue;
            if(core[i][j]==var) {
                leftUPToDown++;
            }else {
                leftUPToDown=0;
            }
            if(leftUPToDown==5) return var;
        }
        //從左下到右上
        int leftDownToUP = 0;
        for(int i=x+4,j=y+4;i>x-5&&j>y-5;i--,j--) {
            if(i<0||i>=this.x||j<0||j>=this.y) continue;
            if(core[i][j]==var) {
                leftDownToUP++;
            }else {
                leftDownToUP=0;
            }
            if(leftDownToUP==5) return var;
        }
        return 0;
    }
    /**
     * 在該位置下棋  1:white 2:black 
     * @param x 橫座標
     * @param y 縱座標
     * @param var 棋子種類
     * @return 1:white 贏   2:black贏
     */
    public int ChessIt(int x,int y,int var) {
        if(__CanInput(x,y)) {
            core[x][y] =var;
            Chess chess = new Chess(x,y);
            stack.push(chess);
            return checkVictory(x, y, var);
        }
        else return -1;
    }
    //悔棋
    public boolean RetChess() {
        if(stack.isEmpty()) return false;
        Chess chess = stack.pop();
        core[chess.x][chess.y]= 0;
        return true;
    }
    //得到棋盤狀態
    public int[][] getCore(){
        return this.core;
    }
    //從新開始
    public void Restart() {
        for(int i=0;i<this.x;i++) {
            for(int j=0;j<this.y;j++) {
                this.core[i][j]=0;
            }
        }
        this.stack.clear();
    }
}

Windows的前端代碼

 

在上一步咱們把一個五子棋的數據結構實現了以後,咱們下一步就須要用JavaSwing的知識來畫前端。

首先咱們定義一個類來繼承JFrame,從而包含JFrame的全部功能。

如下是JFrame經常使用的方法。

jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//關閉JFrame時運行System.exit(0)
jFrame.setLocationRelativeTo(null);//屏幕中央顯示
jFrame.setVisible(true);//可見

 

其次咱們須要單擊屏幕進行下棋,因此咱們須要符合鼠標單擊事件的接口。所以咱們去接上MouseListener的接口。

關於MouseListener接口的介紹以下:

鼠標監聽器MouseListener
監聽鼠標事件MouseEvent。

相應事件和處理方法
鼠標事件         處理方法
MOUSE_CLICKED    MouseClicked (MouseEvent)    鼠標點擊(單或雙)
MOUSE_PRESSED    MousePressed (MouseEvent)    鼠標按下
MOUSE_RELEASED   MouseReleased(MouseEvent)    鼠標鬆開
MOUSE_ENTERED    MouseEntered (MouseEvent)    鼠標進入(某組件區域)
MOUSE_EXITED     MouseExited  (MouseEvent)    鼠標離開(某組件區域)
鼠標事件MouseEvent經常使用方法
int getClickCount()      獲得點擊次數1 OR 2int getX(), int getY()   獲得鼠標的(象素)位置。

鼠標監聽器MouseMotionListener
對於鼠標的移動和拖放,另外用鼠標運動監聽器MouseMotionListener。
由於許多程序不須要監聽鼠標運動,把二者分開可簡化程序。
相應事件和處理方法
鼠標事件          處理方法
MOUSE_MOVED      MouseMoved  (MouseEvent)    鼠標在移動
MOUSE_DRAGGED    MouseDragged(MouseEvent)    鼠標被拖動

 

再而後咱們重寫JFrame裏的paint方法來畫畫。

具體體現:以下

其中橫線和豎線都是調用的Graphics中的drawLine方法。

畫圈圈用的是drawOval和fillOval分別是畫空心圓和畫實心圓。

@Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);
        //
        for (int i = 0; i < 19; i++)
            g.drawLine(30, 30 + i * 30, 570, 30 + i * 30);
        // 豎線
        for (int i = 0; i < 19; i++)
            g.drawLine(30 + i * 30, 60, 30 + i * 30, 570);

        int[][] board = core.getCore();
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                if (board[i][j] == 1)
                    g.drawOval(20 + i * 30, 50 + j * 30, 20, 20);
                if(board[i][j]==2)
                    g.fillOval(20+i*30, 50+j*30, 20, 20);
            }
        }
        g.drawRect(690,60, 50, 30);
        g.drawString("悔棋",700,80);
        g.drawRect(690,120,50, 30);
        g.drawString("開始",700,140);
        g.drawRect(690,180,50, 30);
        g.drawString("設置",700,200);
        g.drawString("Code by 禿桔子 QQ:1243137612", 600,260);
    }

 

再而後咱們須要肯定每次鼠標單擊的事件和信息。

具體實現以下:

@Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        if (e.getX() < 570 && e.getY() < 570) {
            int a = core.ChessIt(_CgetX(e.getX()), (_CgetY(e.getY())), var);
            this.repaint();
            if (a == 1) {
                JOptionPane.showMessageDialog(null,"白的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);;
            }
            if(a==2) {
                JOptionPane.showMessageDialog(null,"黑的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);;
            }
            if(a!=-1) {
                if(var==1) var=2;
                else if(var==2) var=1;
            }
        }
        else if(e.getX()>690&&e.getX()<760&&e.getY()>60&&e.getY()<90) {
            core.RetChess();
            if(var==1) var=2;
            else if(var==2) var=1;
            this.repaint();
        }
        if(e.getX()>690&&e.getX()<760&&e.getY()>120&&e.getY()<150) {
            core.Restart();
            this.repaint();
        }
        if(e.getX()>690&&e.getX()<760&&e.getY()>180&&e.getY()<210) {
            Object[] options = {"白先","黑先"};
            int n = JOptionPane.showOptionDialog(null,"紅先仍是黑先?","遊戲設置",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE, null,options,options[0]);
            if(n==0) this.var=1;
            if(n==1) this.var=2;
            this.core.Restart();
            this.repaint();
        }
    }

這裏面我調用了一個JOptionPane的組件。該組件的使用的方法通常以下

JOptionPane.showMessageDialog(null, "消息");  
JOptionPane.showMessageDialog(null, "消息", "標題",JOptionPane.WARNING_MESSAGE);  
JOptionPane.showMessageDialog(null, "消息.", "標題",JOptionPane.ERROR_MESSAGE);  
JOptionPane.showMessageDialog(null, "消息.", "標題",JOptionPane.PLAIN_MESSAGE);  

 

再而後每次單擊的時候進行repaint重繪將代碼重寫出來。

 

這些東西我也不記得,看api就行了。

下面是整體源碼:

package main;

import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
/**
 * 
 * @author GodofOrange
 * @see 圖形界面
 */
public class Windows extends JFrame implements MouseListener {
    public Core core;
    private static final long serialVersionUID = 1L;
    private int var = 1;
    public Windows(String title) {
        super(title);
        core = new Core(19, 19);
        this.setSize(800, 600);
        this.setLocation(800, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setResizable(false);
        this.addMouseListener(this);
    }

    @Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);
        //
        for (int i = 0; i < 19; i++)
            g.drawLine(30, 30 + i * 30, 570, 30 + i * 30);
        // 豎線
        for (int i = 0; i < 19; i++)
            g.drawLine(30 + i * 30, 60, 30 + i * 30, 570);

        int[][] board = core.getCore();
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                if (board[i][j] == 1)
                    g.drawOval(20 + i * 30, 50 + j * 30, 20, 20);
                if(board[i][j]==2)
                    g.fillOval(20+i*30, 50+j*30, 20, 20);
            }
        }
        g.drawRect(690,60, 50, 30);
        g.drawString("悔棋",700,80);
        g.drawRect(690,120,50, 30);
        g.drawString("開始",700,140);
        g.drawRect(690,180,50, 30);
        g.drawString("設置",700,200);
        g.drawString("Code by 禿桔子 QQ:1243137612", 600,260);
    }

    @Override
    public void mouseClicked(MouseEvent arg0) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        if (e.getX() < 570 && e.getY() < 570) {
            int a = core.ChessIt(_CgetX(e.getX()), (_CgetY(e.getY())), var);
            this.repaint();
            if (a == 1) {
                JOptionPane.showMessageDialog(null,"白的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);;
            }
            if(a==2) {
                JOptionPane.showMessageDialog(null,"黑的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);;
            }
            if(a!=-1) {
                if(var==1) var=2;
                else if(var==2) var=1;
            }
        }
        else if(e.getX()>690&&e.getX()<760&&e.getY()>60&&e.getY()<90) {
            core.RetChess();
            if(var==1) var=2;
            else if(var==2) var=1;
            this.repaint();
        }
        if(e.getX()>690&&e.getX()<760&&e.getY()>120&&e.getY()<150) {
            core.Restart();
            this.repaint();
        }
        if(e.getX()>690&&e.getX()<760&&e.getY()>180&&e.getY()<210) {
            Object[] options = {"白先","黑先"};
            int n = JOptionPane.showOptionDialog(null,"紅先仍是黑先?","遊戲設置",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE, null,options,options[0]);
            if(n==0) this.var=1;
            if(n==1) this.var=2;
            this.core.Restart();
            this.repaint();
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    private int _CgetX(int x) {
        x -= 30;
        if (x % 15 <= 7)
            return x / 30;
        else
            return x / 30 + 1;
    }

    private int _CgetY(int y) {
        y -= 60;
        if (y % 15 <= 7)
            return y / 30;
        else
            return y / 30 + 1;
    }
}

而後就是啓動函數了

這個函數放哪都行-.-。。。。。一看就懂吧?

package main;

public class Main {
    /** 啓動函數
     * @param args
     */
    public static void main(String[] args) {
        new Windows("五子棋");
    }
}

 

 

總結:

其實五子棋的小程序對於初學者來講並不簡單。不適合作練手項目,不過當代碼量積累到必定程度,寫這個小程序簡直不要過輕鬆。完成起來分分鐘鍾。必定要打好數據結構的基礎並加大代碼量。

相關文章
相關標籤/搜索