• 技术文章 >Java >java教程

    java如何实现联机五子棋

    WBOYWBOY2023-04-19 23:40:12转载29

    下面是客户端运行的效果:

    这里是代码包的结构:

    接着我来依次说下这些类所完成的功能

    Media包

    Media包:主要是放了五子棋的背景图片和播放音乐的类以及音乐内容

    播放音乐这个类是我从室友那拿的,所以我也不是很懂,瞄了一眼是用Applet完成的,只能处理.wav后缀的音乐

    Net包

    Net包:包含两个类,细心的小伙伴应该注意到客户端是没有主方法的。客户端中其实是包含与服务端进行通信的socket的,其中包含一些读和写的方法。服务端我采用的是线程池的方法来处理客户端的请求(线程池这部分我也不是特别了解,用起来和多线程感觉差不多)。

    View包

    View包:包含四个类,分别是ChessBoard,ChessPanel,Pieces和WhoWin 类

    ChessBoard是一个包含Main方法的JFrame,命令面板和棋盘面板都是添加到这个JFrame中的。

    ChessPanel是一个棋盘面板,里面完成了如:画19*19的棋盘线条,加载背景图片,不停的接收来自服务端的消息并处理(把棋子加到面板),处理每次点击后添加棋子到面板并发送棋子到服务器,判断胜负并且给出提示消息。

    Pieces是一个棋子,其中有包含如颜色,棋子半径,棋子位置和命令(和前面的命令面板配合使用,默认是发送)等属性。

    WhoWin就是五子棋中判断谁输谁赢的部分。每下一步就需要判断。

    播放音乐的类:

    package Media.Music;
    import java.io.File;
    import java.io.IOException;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    public class PlayMusic {
        private Clip clip;
        public PlayMusic(String filePath) throws LineUnavailableException, UnsupportedAudioFileException, IOException {
            File file = new File(filePath);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
            clip = AudioSystem.getClip();
            clip.open(audioInputStream);
        }
     
        public void play() {
            clip.setFramePosition(1);
            clip.start();
        }
     
        public void loop() {
            clip.loop(Clip.LOOP_CONTINUOUSLY);
        }
        public void stop() {
            clip.stop();
        }
    }

    TcpClient:

    package net;
    import view.Pieces;
    import java.io.*;
    import java.net.Socket;
    public class TcpClient{
        private Socket socket;
        private ObjectInputStream ois;
        private ObjectOutputStream oos;
        public TcpClient(Socket socket,ObjectInputStream ois,ObjectOutputStream oos){
            this.socket= socket;
            this.ois = ois;
            this.oos = oos;
        }
        public Socket getSocket() {
            return socket;
        }
     
        public void setSocket(Socket socket) {
            this.socket = socket;
        }
     
        public ObjectInputStream getOis() {
            return ois;
        }
     
        public void setOis(ObjectInputStream ois) {
            this.ois = ois;
        }
     
        public ObjectOutputStream getOos() {
            return oos;
        }
     
        public void setOos(ObjectOutputStream oos) {
            this.oos = oos;
        }
     
        public void send(Pieces pieces) throws IOException {
            oos.writeObject(pieces);
            System.out.println(socket+"向服务器发送消息");
        }
        public Pieces accept() throws IOException, ClassNotFoundException {
            Pieces pieces = (Pieces) ois.readObject();
            System.out.println(socket+"从服务器读取消息");
            return pieces;
        }
        public void close(){
            ;
        }
    }

    TcpServer:

    package net;
    import view.Pieces;
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.ArrayList;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class TcpServer {
        public static void main(String[] args) {
            // 保存客户端处理的线程
            ArrayList<UserThread> userList = new ArrayList<>();
            // 固定大小的线程池只支持两个线程,用来处理客户端
            ExecutorService es = Executors.newFixedThreadPool(2);
            try {
                ServerSocket server = new ServerSocket(10086);
                System.out.println("服务器已经启动,正在等待客户端连接......");
                while (true) {
                    //接收客户端的Socket,如果没有客户端连接就一直卡在这里
                    Socket socket = server.accept();
                    // 每来一个用户就创建一个线程
                    UserThread user = new UserThread(socket, userList);
                    // 开启线程
                    es.execute(user);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
     
    class UserThread implements Runnable {
        private Socket socket = null;
        private static ArrayList<UserThread> list; // 客户端线程集合
        private ObjectOutputStream oos;
        private ObjectInputStream ois;
        private boolean flag = true;// 标记
     
        public UserThread(Socket socket, ArrayList<UserThread> list) {
            this.socket = socket;
            this.list = list;
            list.add(this); // 把当前线程加入list中
        }
     
        @Override
        public void run() {
            UserThread user = null;
            try {
                System.out.println("客户端:" + socket.getInetAddress().getHostAddress() + "已经连接");
                ois = new ObjectInputStream(socket.getInputStream());
                oos = new ObjectOutputStream(socket.getOutputStream());
                while(true){
                    Pieces pieces = (Pieces) ois.readObject(); // 客户端发给服务端的消息,把他写到其它套接字中去
                    int size = list.size();
                    for (int i = 0; i < size; i++) {
                        user = list.get(i);
                        if (user.socket != socket) {
                            user.oos.writeObject(pieces);
                            System.out.println("从"+socket+"向"+user.socket+"发送消息");
                        }
                    }
                }
            } catch(SocketException e){ //  todo 客户端掉线后,移除客户端。没想好{1.从客户端列表移除当前元素,关闭当前:socket,通知另一方:这一方已经掉线,然后关闭这一方的socket}
                try {
                    int i = list.size();
                    if (i ==2){
                        list.remove(user);
                        System.out.println("已经删除了一个客户端");
                        list.get(0).oos.writeObject(new Pieces("对方掉线"));
                    }else if (i==1){
                        list.remove(0);
                        System.out.println("又移除了另一个客户端");
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    ChessBoard:

    /*
    * 1.变量值不变的问题
    * 2.输入输出流先后顺序的问题(socket阻塞)
    * 3.socket 短连接不关闭输入输出流,为何看起来就像长连接一样(长短连接的区别是什么)
    * */
    // todo 一个提示框
    package view;
    import Media.Music.PlayMusic;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    public class ChessBoard extends JFrame implements ActionListener {
        private JButton PlayMusic = new JButton("播放音乐");
        private ChessPanel chessPanel;
        private Panel CommandPanel = new Panel();
        private JButton reStart = new JButton("重新开始");
        private JButton fail = new JButton("认输");
        private JButton Regret = new JButton("悔棋");
        private String command=null; // 触发按钮后发送的命令
        private PlayMusic music = null;
        private int count = 1;
        //  todo 静态语句块
        {
            try {
                music = new PlayMusic("./src/Media/Music/bg3.wav");
            } catch (LineUnavailableException e) {
                e.printStackTrace();
            } catch (UnsupportedAudioFileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
     
        public ChessBoard() {
            this.setTitle("欢乐五子棋");
            chessPanel = new ChessPanel();
            this.add(chessPanel,BorderLayout.CENTER);
            reStart.addActionListener(this);
            fail .addActionListener(this);
            Regret.addActionListener(this);
            PlayMusic.addActionListener(this);
            CommandPanel.add(reStart);
            CommandPanel.add(fail);
            CommandPanel.add(Regret);
            CommandPanel.add(PlayMusic);
            this.add(CommandPanel,BorderLayout.SOUTH);
            this.setBounds(10, 10, 800, 800);
            this.setVisible(true);
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
        public static void main(String[] args) {
            ChessBoard Board = new ChessBoard();
     
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            if(e.getSource()==reStart){
                command ="重新开始";
                chessPanel.canPlay = true;
            }else if(e.getSource()==fail){
                command ="认输";
                JOptionPane.showMessageDialog(chessPanel,"It's a pity,you have fail the game!");
                chessPanel.canPlay = false;
            }else if (e.getSource()==Regret){
                command ="悔棋";
            }else if (e.getSource()==PlayMusic){
                // todo 播放音乐,单数次播放;
                if (count%2==1){
                    music.play();
                }else {
                    music.stop();
                }
                count++;
                command = null;
            }
            if(command!=null){
                Pieces pieces = new Pieces(command);
                try {
                    this.chessPanel.client.send(pieces);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
     
        }
    }

    ChessPanel:

    package view;
    // 五子棋面板,就是在这里面画图。
    // todo 背景图片 ,也许一个背景音乐
    import net.TcpClient;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ConnectException;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Iterator;
    public class ChessPanel extends JPanel implements MouseListener{
        // TODO 从服务器接收来的棋子 ,值不变有问题
    //   Pieces accept_pieces = new Pieces();
    //   Pieces send_pieces = new Pieces();
        whoWin ifWin =new whoWin() ; // 是否胜利
        TcpClient client = null; // 客户端
        boolean canPlay = true; // 是否能继续玩
        boolean isBlack = true; // 是否黑子,黑1,白2
        ArrayList<Pieces> allPieces = new ArrayList<>(); // 存储棋子对象,就是通过这个画图的
        int [][] allChess = new int[19][19];
        int PanelWidth;
        int PanelHeight;
        int width = 600;
        int height = 600;
        int temp = width / 18;
        int xbase,ybase;
        Image image = Toolkit.getDefaultToolkit().getImage("./src/Media/bg.jpeg"); // "./"表示当前项目下
        public ChessPanel(){
            this.addMouseListener(this);
            try {
                Socket socket = new Socket("172.27.29.190", 10086);
                //TODO 构建输出输入流,输入输出流问题,先输出后输入
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                client = new TcpClient(socket,ois,oos);
                new Thread(new getMessage()).start(); // 开启读取的线程
            } catch (ConnectException e){
                System.out.println("服务器拒绝连接!");
            } catch (IOException e) {
                e.printStackTrace();
            }catch(Exception e ){
                e.printStackTrace();
            }
        }
        // 画图部分
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            PanelWidth = this.getSize().width; // 这两步骤
            PanelHeight = this.getSize().height;
            xbase = (PanelWidth - width) / 2;
            ybase = (PanelHeight - height) / 2;
            Graphics2D g2d = (Graphics2D) g;
    //        this.setBackground(new Color(246, 186, 114));
            g2d.drawImage(image,0,0,this.getWidth(),this.getHeight(),this);
            int x1, y1, x2, y2;
            // 画线
            for (int i = 0; i < 19; i++) {
                if (i == 0 || i == 18) {
                    g2d.setStroke(new BasicStroke(3.0f));
                } else g2d.setStroke(new BasicStroke(1.0f));
                x1 = xbase + temp * i;
                y1 = ybase;
                y2 = ybase + 18 * temp;
                g2d.drawLine(x1, y1, x1, y2);
                x1 = xbase;
                y1 = ybase + temp * i;
                x2 = xbase + temp * 18;
                g2d.drawLine(x1, y1, x2, y1);
            }
            // 开始画棋子
            int radius ;
            int xPos,yPos;
            Iterator it = allPieces.iterator(); // 迭代器遍历arraylist
            while(it.hasNext()){
                Pieces pieces = (Pieces) it.next();
                radius  = pieces.getRadius();
                xPos = pieces.getxPos();
                yPos = pieces.getyPos();
                System.out.println(pieces.getColor()+","+pieces.getxPos()+","+pieces.getyPos());
                if (pieces.getColor() == 1){
                    g2d.setColor(Color.black);
                    g2d.fillOval(xPos*temp+xbase-radius/2,yPos*temp+ybase-radius/2,radius,radius);
                }
                else if (pieces.getColor() == 2) {
                    g2d.setColor(Color.white);
                    g2d.fillOval(xPos * temp + xbase - radius / 2, yPos * temp + ybase - radius / 2, radius, radius);
                }
            }
     
        }
     
        @Override
        public void mousePressed(MouseEvent e) {
            int x ,y ;
            if (canPlay) {
                x = e.getX();
                y = e.getY();
                //  判断鼠标点击位置
                if (x >= xbase & x <= (xbase + 18 * temp) & y >= ybase & y < (ybase + 18 * temp)) {
                    // 判断是不是下在空的位置
                    int tempX = (x - xbase) / temp, tempY = (y - ybase) / temp;
                    // todo 这里是关键判断这点坐标的数组下标是什么
                    if ((x - xbase) % temp > temp / 2) {
                        x = tempX + 1;
                    } else
                        x = tempX;
                    if ((y - ybase) % temp > temp / 2)
                        y = tempY + 1;
                    else
                        y = tempY;
                    // 先判断有没有棋子,处理没有棋子的情况
                    if (allChess[x][y] != 0) {
                           JOptionPane.showMessageDialog(this, "这里有棋子了");
                    } else {
                        Pieces send_pieces = new Pieces();
                        send_pieces.setxPos(x);
                        send_pieces.setyPos(y);
                        if (isBlack){
                            send_pieces.setColor(1);
                            allChess[x][y] = 1;
                            isBlack = false;
                        }
                        else{
                            send_pieces.setColor(2);
                            allChess[x][y]=2;
                            isBlack = true;
                        }
                        allPieces.add(send_pieces); // 向棋子队列加入当前棋子
                        canPlay = false;// canPlay在true情况下, 点击一次后不能点击了
                        this.repaint();
                        ifWin = new whoWin(allChess,x,y);
                        // 如果赢了,就不能玩了,并且给出提示消息,你赢了;
                        if(ifWin.isWin()){
                            canPlay = false;
                            JOptionPane.showMessageDialog(this,"Congratulations you have won tha game !");
                        }
                        try {
                            if (client!=null){
                                client.send(send_pieces);
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
     
            }
        }
     
        // 读取来自服务器端的信息
        class getMessage implements Runnable{
            private boolean flag = true;
            public void setFlag(boolean flag) {
                this.flag = flag;
            }
     
            @Override
            public void run() {
                // 循环读
                while(flag){
                    if(client!=null){
                        try {
                            Pieces accept_pieces = client.accept();
                            String command = accept_pieces.getCommand();
                            int color = accept_pieces.getColor();
                            switch (command){
                                case "发送":{
                                    canPlay = true;
                                    if (color == 1){
                                        isBlack = false;//对方为黑我为白
                                    }else{
                                        isBlack = true;
                                    }
                                    allPieces.add(accept_pieces);
                                    allChess[accept_pieces.getxPos()][accept_pieces.getyPos()]= accept_pieces.getColor();
                                    ChessPanel.this.repaint();
                                    ifWin.setY(accept_pieces.getyPos());
                                    ifWin.setX(accept_pieces.getxPos());
                                    ifWin.setAllChess(allChess);
                                    if(ifWin.isWin()){
                                        canPlay = false;
                                        JOptionPane.showMessageDialog(ChessPanel.this,"It's a pity you have fail the game!");
                                    }
                                    break;
                                }
                                case "悔棋":{
                                    int i = JOptionPane.showConfirmDialog(ChessPanel.this,"对方请求悔棋,是否同意!");
                                    // yes 0,no 1,cancel 2,closed -1
                                    Pieces pieces = new Pieces();
                                    if (i == 0){
                                        // 同意悔棋:1.同意对方悔棋
                                        pieces.setCommand("同意悔棋");
                                        // arraylist 去除末尾的两个值,对应allChess置0
                                        int size = allPieces.size();
                                        for (int j = 1;j<=2;j++){
                                            allChess[allPieces.get(size-j).getxPos()][allPieces.get(size-j).getyPos()]=0;
                                            allPieces.remove(size-j);
                                        }
                                        ChessPanel.this.repaint();
                                    }else if(i==1){
                                        pieces.setCommand("不同意悔棋");
                                    }
                                    client.send(pieces);
                                    break;
                                }
                                case "认输":{ // 不能继续玩下去,你已经胜利
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方认输");
                                    canPlay = false;
                                    JOptionPane.showMessageDialog(ChessPanel.this,"Congratulations you have won tha game !");
                                    break;
                                }
                                case "重新开始":{ // 是否同意重新开始
                                   int i = JOptionPane.showConfirmDialog(ChessPanel.this,"对方请求重新开始,是否同意");
                                    Pieces pieces = new Pieces();
                                    if(i == 0){// allChess 和 allPieces全部置0;
                                        pieces.setCommand("同意重新开始");
                                        int size = allPieces.size();
                                        System.out.println("arraylist 长度:"+size);
                                        for (int j = 0;j<size;j++){// 移除队首元素
                                            allChess[allPieces.get(0).getxPos()][allPieces.get(0).getyPos()] = 0;
                                            allPieces.remove(0);
                                        }
                                        canPlay = true;
                                        ChessPanel.this.repaint();
                                    }else if (i ==1){
                                        pieces.setCommand("不同意重新开始");
                                    }
                                    client.send(pieces);
                                    break;
                                }
                                case "同意悔棋":{// allpieces 和 allchess 回退
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方同意悔棋");
                                    int size = allPieces.size();
                                    for (int j = 1;j<=2;j++){
                                        allChess[allPieces.get(size-j).getxPos()][allPieces.get(size-j).getyPos()]=0;
                                        allPieces.remove(size-j);
                                    }
                                    ChessPanel.this.repaint();
                                    break;
                                }
                                case "不同意悔棋":{
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方不同意悔棋");
                                    break;
                                }
     
                                case "同意重新开始":{ // 全部置0,调用repaint 方法
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方同意重新开始");
                                    int size = allPieces.size();
                                    for (int j = 0;j<size;j++){ //  todo 移除队首元素arraylist 长度改变;序列也发生改变
                                        allChess[allPieces.get(0).getxPos()][allPieces.get(0).getyPos()] = 0;
                                        allPieces.remove(0);
                                    }
                                    canPlay = true;
                                    ChessPanel.this.repaint();
                                    break;
                                }
                                case "不同意重新开始":{
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方不同意重新开始");
                                    break;
                                }
                                case "对方掉线":{ // 对方已经掉线
                                    JOptionPane.showMessageDialog(ChessPanel.this,"不好意思,对方已经掉线!");
                                    canPlay = false;
                                    break;
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
     
        @Override
        public void mouseClicked(MouseEvent e) {
     
        }
        @Override
        public void mouseReleased(MouseEvent e) {
     
        }
     
        @Override
        public void mouseEntered(MouseEvent e) {
     
        }
     
        @Override
        public void mouseExited(MouseEvent e) {
     
        }
     
    }

    Pieces:

    package view;
     
    import java.io.Serializable;
    // 存储棋子的相关信息
    public class Pieces implements Serializable {
        private int radius = 16;
        private int color = 0;
        private int xPos ;
        private int yPos;
        private String command = "发送";
        public String getCommand() {
            return command;
        }
     
        public void setCommand(String command) {
            this.command = command;
        }
     
        public Pieces(int color, int xPos, int yPos){
            this.color = color;
            this.xPos = xPos;
            this.yPos = yPos;
        }
        public Pieces(){
     
        }
        public Pieces(String command){
            this.command = command;
        }
        public int getRadius() {
            return radius;
        }
     
        public void setRadius(int radius) {
            this.radius = radius;
        }
     
        public int getColor() {
            return color;
        }
     
        public void setColor(int color) {
            this.color = color;
        }
     
        public int getxPos() {
            return xPos;
        }
     
        public void setxPos(int xPos) {
            this.xPos = xPos;
        }
     
        public int getyPos() {
            return yPos;
        }
     
        public void setyPos(int yPos) {
            this.yPos = yPos;
        }
    }

    WhoWin:

    package view;
    public class whoWin { // 判断是谁赢了
        private int allChess[][] = new int[19][19];
        private int x = 0;
        private int y = 0;
        public whoWin(){
     
        }
        public whoWin(int allChess[][],int x,int y){
            this.allChess = allChess;
            this.x = x;
            this.y = y;
        }
     
        public void setAllChess(int allChess[][]){
            this.allChess = allChess;
        }
        public void setX(int x){
            this.x = x;
        }
        public void setY(int y ){
            this.y = y;
        }
        public boolean isWin() {
            int color = allChess[x][y];
            int count;
            count = this.Count(1, 0, color); // 对横方向的判断
            if (count >= 5) {
                return true;
            } else {
                count = this.Count(0, 1, color); // 对竖方向的判断
                if (count >= 5) {
                    return true;
                } else {
                    count = this.Count(1, 1, color); // 对左上方向的判断
                    if (count >= 5)
                        return true;
                    else {
                        count = this.Count(1, -1, color); // 对右上方向的判断
                        if (count >= 5)
                            return true;
                    }
                }
            }
            return false;
        }
        private int Count(int xChange, int yChange, int color) {
            int count = 1;
            int tempX = xChange, tempY = yChange;
            while (color == allChess[x + xChange][y + yChange]) {
                count++;
                if (xChange != 0) {
                    xChange++;
                }
                if (yChange != 0) {
                    if (yChange > 0)
                        yChange++;
                    else
                        yChange--;
                }
            }
            xChange = tempX;
            yChange = tempY;
            while (color == allChess[x - xChange][y - yChange]) {
                count++;
                if (xChange != 0)
                    xChange++;
                if (yChange != 0) {
                    if (yChange > 0)
                        yChange++;
                    else
                        yChange--;
                }
            }
            return count;
        }
    }

    以上就是java如何实现联机五子棋的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:亿速云,如有侵犯,请联系admin@php.cn删除
    专题推荐:Java
    上一篇:java如何实现登录窗口 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 如何在Java中压缩文件并提供下载• Java与Scala中的偏函数与偏应用函数的使用方法• Java内部类的访问方式是什么?• 使用Java编写猴子吃桃问题的解决方案• Java编程实现群聊应用程序,使用MulticastSocket实现
    1/1

    PHP中文网