Maison  >  Article  >  Java  >  Comment implémenter le backgammon en ligne en Java

Comment implémenter le backgammon en ligne en Java

WBOY
WBOYavant
2023-04-19 23:40:12896parcourir

Ce qui suit est l'effet de l'exécution du client :

Comment implémenter le backgammon en ligne en Java

Voici la structure du package de code :

Comment implémenter le backgammon en ligne en Java

Ensuite, laissez-moi parler des fonctions remplies par ces classes à tour de rôle

Pack média

Package média : Principal Il contient l'image de fond du backgammon et le cours pour jouer de la musique ainsi que le contenu musical

J'ai reçu ce cours pour jouer de la musique de mon colocataire, donc je ne le comprends pas très bien, j'y ai jeté un coup d'œil. a été réalisé à l'aide d'une applet, qui ne peut traiter que la musique avec suffixe .wav

Package Net

Package Net : contient deux classes. Les amis attentifs doivent remarquer que le client n'a pas de méthode principale. Le client contient en fait un socket pour communiquer avec le serveur, qui contient des méthodes de lecture et d'écriture. Côté serveur, j'utilise la méthode du pool de threads pour gérer les requêtes des clients (je ne connais pas grand-chose au pool de threads et cela ressemble au multi-threading).

View package

View package : contient quatre classes, à savoir ChessBoard, ChessPanel, Pieces et WhoWin class

ChessBoard est un JFrame contenant la méthode Main Le panneau de commande et le panneau d'échiquier sont ajoutés à ce JFrame.

ChessPanel est un panneau d'échiquier qui effectue des tâches telles que : dessiner 19*19 lignes d'échiquier, charger des images d'arrière-plan, recevoir et traiter en permanence les messages du serveur (ajouter des pièces d'échecs au panneau) et traiter l'ajout de pièces d'échecs après chaque clic. . Accédez au panneau et envoyez les pièces d'échecs au serveur, déterminez le résultat et envoyez un message rapide.

Pièces est une pièce d'échecs qui contient des attributs tels que la couleur, le rayon de la pièce, la position de la pièce d'échecs et la commande (utilisée conjointement avec le panneau de commande précédent, la valeur par défaut est d'envoyer).

WhoWin est la partie du backgammon qui détermine qui perd et qui gagne. Chaque étape suivante nécessite du jugement.

Classe pour jouer de la musique :

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&#39;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&#39;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) {
 
    }
 
}

Pièces:

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;
    }
}

Who Gagner :

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;
    }
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer