JavaSE:实现象棋游戏

文章目录

  • 1. 每日一言
  • 2. 游戏内容介绍
  • 3. 代码介绍
  • 4. 全部代码
    • 4.1 MainFream
    • 4.2 GamePanel
    • 4.3 ChessFactory
    • 4.4 Bing
    • 4.5 Boss
    • 4.6 Che
    • 4.7 Chess
    • 4.8 Ma
    • 4.9 Pao
    • 4.10 Shi
    • 4.11 Xiang
  • 结语

1. 每日一言

Every cloud has a silver lining.
天无绝人之路。


2. 游戏内容介绍

象棋是一种中国传统的棋类游戏,也是世界上最古老、最普及的棋类之一。象棋使用一个棋盘,上面有64个方格,棋盘被分成红棋和黑棋两方,每方有16个棋子。

棋子分别为:帅(将)、仕(士)、相(象)、马、车、炮和兵(卒)。每个棋子都有特定的移动方式和规则。帅/将是最重要的棋子,每方的目标就是要将对方的帅/将困住,使其无法移动。

象棋的游戏目标是要将对方的帅/将逼到无路可走的境地,即将军,并且无论如何对方都无法避免被将军,这就是将军、绝杀的最佳状态,获胜方即为胜利。

本游戏实现了"自弈"功能

游戏截图:
在这里插入图片描述

在这里插入图片描述

3. 代码介绍

该程序使用的GUI为 swing,听说已经过时了。他给我的感受就是,十分难用,而且还丑,也可能是因为我只了解一点点吧。

  1. MainFream 该类是用来管理游戏的总框架,也是程序的入口
  • 其中定义了一个简单的主界面窗口,包含了一个游戏面板和一些按钮,读者可以根据需要进行扩展和实现相应的功能。
  1. GamePanel 该类用来控制游戏面板
    • 主要功能包括:
      创建棋子并将棋子放到数组中
      通过点击事件,判断棋子的选择、移动和吃子操作
      绘制棋盘和棋子的图像
      其中的creatChesses()方法用于创建棋子并将棋子保存到数组中。每个棋子都有一个名称、阵营和网格坐标。棋子的名称、阵营和网格坐标通过数组和循环进行设置。
      MouseAdapter类用于处理鼠标点击事件。在点击事件中,通过获取鼠标点击的坐标,判断是否选中了棋子。根据不同的情况,进行重新选择、移动或吃子操作。在操作完成后,刷新棋盘。
      paint()方法用于绘制棋盘和棋子的图像。首先通过图片路径获取图片对象,然后使用drawImage()方法将图片绘制到面板上。最后调用drawChesses()方法画出棋子的图像。如果有棋子被选中,通过drawRect()方法在棋子周围画出一个矩形框。
  2. ChessFactory 顾名思义,该类用来快速生成棋子
    • 这段代码是一个棋子工厂类。它的作用是根据输入的棋子名称、玩家和位置信息来创建对应的棋子对象。棋子对象根据不同的名称会有不同的移动规则。如果输入的名称是"boss",则创建一个Boss棋子对象
  3. Bing 该类管理兵这个棋子
  4. Boss 该类管理将/帅这个棋子
  5. Che 该类管理车这个棋子
  6. Chess 该类为抽象类用来辅助生成棋子以及判断棋子的前进方式
  7. Ma 该类管理马这个棋子
  8. Pao 该类管理炮这个棋子
  9. Shi 该类管理士这个棋子
  10. Xiang 该类管理象这个棋子

具体可以看代码中的注释。

4. 全部代码

4.1 MainFream

package com.code.main;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

//主界面
public class MainFream extends JFrame implements ActionListener {
    public MainFream() {
        //设置窗口大小
        setSize(480,480);
//        setSize(580,500);
        //设置窗口居中
        setLocationRelativeTo(null);
        //设置点击关闭按钮同时结束虚拟机
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置布局管理员
        setLayout(new BorderLayout());
        //将游戏面板添加到窗口中
        GamePanel gp = new GamePanel();
        add(gp, BorderLayout.CENTER);
        //添加按钮面板
        JPanel btnPanel = new JPanel(new GridLayout(4,1));
        //add(btnPanel,BorderLayout.EAST);
        add(btnPanel,BorderLayout.EAST);
        JLabel hintLabel = new JLabel("红方走");
        btnPanel.add(hintLabel);
        gp.setHintLabel(hintLabel);
//        JButton btnHuiQi = new JButton("悔棋");
//        btnHuiQi.setActionCommand("huiqi");
//        btnHuiQi.addActionListener(this);
//        btnPanel.add(btnHuiQi);
//        JButton btnSave = new JButton("保存棋谱");
//        btnSave.setActionCommand("baocun");
//        btnSave.addActionListener(this);
//        btnPanel.add(btnSave);
//        JButton btnImport = new JButton("导入棋谱");
//        btnImport.setActionCommand("daoru");
//        btnImport.addActionListener(this);
//        btnPanel.add(btnImport);
//        JButton btnQiuHe = new JButton("求和");
//        btnQiuHe.setActionCommand("qiuhe");
//        btnQiuHe.addActionListener(this);
//        btnPanel.add(btnQiuHe);
//        JButton btnRenShu= new JButton("认输");
//        btnRenShu.setActionCommand("renshu");
//        btnRenShu.addActionListener(this);
//        btnPanel.add(btnRenShu);
        //设置窗口可见,建议放在后面
        setVisible(true);
    }
    public static void main(String[] args) {
        //JFrame frm = new JFrame();
        //JFrame默认是一个看不见的窗口

        new MainFream();//匿名对象
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("按钮被点击了");
        //获取按钮的ActionCommand
        String cmd = e.getActionCommand();
        switch (cmd) {
            case "huiqi":
                System.out.println("huiqi");
                break;
            case "baocun":
                System.out.println("baocun");
                break;
            case "daoru":
                System.out.println("daoru");

                break;
            case "qiuhe":
                System.out.println("qiuhe");

                break;
            case "renshu":
                System.out.println("renshu");

                break;
        }
    }
}

4.2 GamePanel

package com.code.main;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Arrays;

//游戏面板
public class GamePanel extends JPanel {
    private Chess[] chesses = new Chess[32];//保存所有棋子

    private Chess selectedChess;//当前选中的棋子

    //记住当前阵营
    private int curPlayer = 0;//红方先手

    private JLabel hintLabel;

    public void setHintLabel(JLabel hintLabel) {
        this.hintLabel = hintLabel;
    }

    public GamePanel() {
        creatChesses();

        /*  如何操作棋子
                1 点击棋盘
                2 如何获取棋子对象(如何判断点击的地方是否有棋子)
                3 如何区分选择,重新选择,移动,吃子

            棋盘规则
                1 红方不能操作黑方的棋子
                2 一方走完,另一方才能走
         */

        //添加点击事件
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //通过e可以获得鼠标点击的坐标
                Point p = Chess.getPointFromXY(e.getX(),e.getY());
                if(selectedChess == null) {
                    //没选过棋子
                    selectedChess = getChessByP(p);
                    if(selectedChess != null && selectedChess.getPlayer() != curPlayer) {
                        //选了对面的棋子
                        selectedChess = null;
                        hintLabel.setText("<html> 不能选择对方的棋子<br/> " + (curPlayer == 0 ? "红方走" : "黑方走") + "</html>");
                    }
                }else {
                    //重新选择,移动,吃子
                    Chess c = getChessByP(p);
                    if(c != null) {
                        //第n次点击的时候有棋子
                        //重新选择,吃子
                        if(c.getPlayer() == selectedChess.getPlayer()) {
                            //重新选择
                            System.out.println("重新选择");
                            selectedChess = c;
                        }else {
                            //吃子
                            System.out.println("吃子");
                            if(selectedChess.isAbleMove(p,GamePanel.this)) {
                                /*  从数组中删除被吃掉的棋子
                                    修改要移动的棋子
                                 */
                                chesses[c.getIndex()] = null;
                                if(c.getIndex() == 4) {
                                    hintLabel.setText("红方获胜");
//                                    while (true) {
//                                        try {
//                                            Thread.sleep(1000);
//                                        } catch (InterruptedException ex) {
//                                            throw new RuntimeException(ex);
//                                        }
//                                    }
                                } else if (c.getIndex() == 20) {
                                    hintLabel.setText("黑方获胜");
//                                    while (true) {
//                                        try {
//                                            Thread.sleep(1000);
//                                        } catch (InterruptedException ex) {
//                                            throw new RuntimeException(ex);
//                                        }
//                                    }
                                } else {
                                    selectedChess.setP(p);
                                    overMyTurn();
                                }

                            }
                        }
                    }else {
                        //第n次点击的时候没有棋子,点的是空地
                        //移动
                        System.out.println("移动");
                        if(selectedChess.isAbleMove(p,GamePanel.this)) {
                            selectedChess.setP(p);
                            overMyTurn();
                        }
                    }
                }
                //System.out.println("点击的棋子对象为:" + selectedChess);
                //刷新棋盘,即重新执行paint方法
                repaint();
            }
        });
    }

    //一方走完了,换成另一方走
    private void overMyTurn() {
        curPlayer = curPlayer == 0 ? 1 : 0;
        //将选择的棋子放下
        selectedChess = null;
        hintLabel.setText(curPlayer == 0 ? "红方走" : "黑方走");
    }

    //查找棋子对象
    public Chess getChessByP(Point p) {
        for (Chess item : chesses) {
            if(item != null && item.getP().equals(p)) {
                return item;
            }
        }
        return null;
    }

    //创建棋子并将棋子放到数组中
    private void creatChesses() {
        String[] names = {"che","ma","xiang","shi","boss","shi","xiang","ma","che","pao","pao","bing","bing","bing","bing","bing"};
        int[] xs = {1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 8, 1, 3, 5, 7, 9};
//        for (int i = 0; i < names.length; i++) {
            Chess c = new Chess(names[i],1,ps[i]);
            c.setName(names[i]);
            c.setP(ps[i]);//指定棋子的网格坐标
            c.setPlayer(1);//设置阵营
//            Chess c = ChessFactory.create(names[i],0,xs[i]);
//
//            c.reserve();
//            c.setIndex(i+16);
//            chesses[c.getIndex()] = c;
//        }
        for (int i = 0; i < names.length; i++) {
           Chess c = ChessFactory.create(names[i],1,xs[i]);
//            c.setName(names[i]);
//            c.setP(ps[i]);//指定棋子的网格坐标
//            c.setPlayer(0);//设置阵营
            c.setIndex(i);
            chesses[i] = c;//将棋子保存到数组中
            //System.out.println(c);
        }
        for (int i = 0; i < names.length; i++) {
//            Chess c = new Chess(names[i],1,ps[i]);
//            c.setName(names[i]);
//            c.setP(ps[i]);//指定棋子的网格坐标
//            c.setPlayer(1);//设置阵营
            Chess c = ChessFactory.create(names[i],0,xs[i]);

            c.reserve();
            c.setIndex(i+16);
            chesses[c.getIndex()] = c;
        }
    }


    //画棋子
    private void drawChesses(Graphics g) {
        for (Chess item:chesses) {
            if(item != null) {
                item.draw(g,this);
            }

        }
    }
    @Override
    public void paint(Graphics g) {
        //super.paint(g);//清除原来的痕迹

        /*  paint 方法是JPanel的绘制面板内容的方法
            Graphics:绘制类
                常用方法
                    g.drawImage:画图片
                    g.drawChars:画文字
                    g.drawLine:画直线
                    drawOval:画园或椭圆
            如何在Jpanel画一张图1
             1 准备图片路径
                File.separator:路径分隔符
             2 通过图片路径得到图片对象
             3 使用g.drawImage方法将图片绘制到面板上
         */
        //1.准备图片路径
        String bgPath = "pic" + File.separator +  "qipan.jpg";
        //2 通过图片路径得到图片对象
        /*  Toolkit.getDefaultToolkit():获取Toolkit的实例
            createImage():创建图片
            getImage():获取图片
         */
        Image bgImg = Toolkit.getDefaultToolkit().getImage(bgPath);
        //3 使用g.drawImage方法将图片绘制到面板上
        g.drawImage(bgImg,0,0,this);
        /*
            img:要汇总的图片对象
            x:坐标x,在编程中坐标都是从左上角开始,往右是正数
            y:坐标y,往下是正数
            observer:图片观察者,写JPanel对象即可
         */
        //如何画棋子
        /*String Path = "pic" + File.separator +  "che0.png";
        Image img = Toolkit.getDefaultToolkit().getImage(Path);
        //g.drawImage(che0Img,0,0,this);
        g.drawImage(img,5,5,30,30,this);
         */

        drawChesses(g);//画棋子

        if(selectedChess != null) {
            selectedChess.drawRect(g);
        }
    }


}

4.3 ChessFactory

package com.code.main;

//生成棋子
public class ChessFactory {
    private ChessFactory() {

    }

    public static Chess create(String name,int player,int px) {
        //定制棋子移动的规则
        if("boss".equals(name)) {
            return new Boss(player,px);
        }else if("shi".equals(name)){
            return new Shi(player,px);
        }else if("xiang".equals(name)){
            return new Xiang(player,px);
        }else if("ma".equals(name)){
            return new Ma(player,px);
        }else if("che".equals(name)){
            return new Che(player,px);
        }else if("pao".equals(name)){
            return new Pao(player,px);
        }else if("bing".equals(name)){
            return new Bing(player,px);
        }
        return null;
    }

}

4.4 Bing

package com.code.main;

import com.code.main.Chess;
import com.code.main.GamePanel;

import java.awt.*;

public class Bing extends Chess {
    public Bing(int player, Point p) {
        super("bing",player,p);
    }

    public Bing(int player, int px) {
        this(player, new Point(px,4));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
        if(line(tp) < 2 || getStep(tp) > 1) {
                //不是走直线 || 走的步数大于一
                return false;
            }
            if(isOverRiver(p)) {
                //过河 ,不往前后
                return !isBack(tp);
            } else {
                //没过河,只能前进
                return isForward(tp);
            }
    }
}

4.5 Boss

package com.code.main;

import java.awt.*;

public class Boss extends Chess{
    public Boss(int player, Point p) {
        super("boss",player,p);
    }

    public Boss(int player, int px) {
        this(player, new Point(px,1));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
        return line(tp) > 1 && isHome(tp) && getStep(tp) == 1;
    }
}

4.6 Che

package com.code.main;

import java.awt.*;

public class Che extends Chess{
    public Che(int player, Point p) {
        super("che", player, p);
    }

    public Che(int player, int px) {
        this(player, new Point(px,1));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
    	//只能横竖走,并且与目的地之间没有棋子阻挡
        return line(tp) > 1 && getCount(tp,gamePanel) == 0;
    }
}

4.7 Chess

package com.code.main;

import javax.swing.*;
import java.awt.*;
import java.io.File;

public abstract class Chess {
    //棋子大小
    private static final int SIZE = 30;
    //棋盘外边距
    private static final int MARGIN = 20;
    //棋子间距
    private static final int SPACE = 40;
    //棋子名字
    private String name;
    //后缀
    private String suffix = ".png";
    //棋子阵营
    protected int player;

    //绘制时的坐标
    private int x,y;

    //棋子的网格坐标
    protected Point p;

    //棋子的网格坐标,初始位置,不可改变
    private Point initP;

    //保存每个棋子的索引位置
    private int index;
    public void setIndex(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }

    public int isUpOrDown() {
        //上面和下面的棋子
        //1.上
        //2.下
        if(initP.y < 6 ) {
            //上面
            return 1;
        }else if(initP.y > 5) {
            //下面
            return 2;
        }else {
            return 0;
        }
    }

    //判断棋子是否在王宫范围内
    public boolean isHome(Point tp) {
        if(tp.x < 4 || tp.x > 6) {
            return false;
        }
        int upOrDown = isUpOrDown();
        if(upOrDown == 1) {
            //上
            if(tp.y > 3 || tp.y < 1) {
                return false;
            }
        } else if (upOrDown == 2) {
            //下
            if(tp.y > 10 || tp.y < 8) {
                return false;
            }
        }
        return true;
    }

    //判断棋子是否走直线
    //1.走斜线
    //2.y直线
    //3.x直线
    //0. x轴日字
    //-1 y轴日字
    //-2.都不是
    public int line(Point tp) {
        if(p.y == tp.y) {
            //X轴直线
            return 3;
        }else if(p.x == tp.x) {
            //Y轴直线
            return 2;
        }else  if(Math.abs(p.x - tp.x) == Math.abs(p.y - tp.y)) {
            //走斜线
            return 1;
        } else {
            //日字
            if(Math.abs(p.x - tp.x) == 2 && Math.abs(p.y - tp.y) == 1) {
                //x
                return 0;
            } else if (Math.abs(p.x - tp.x) == 1 && Math.abs(p.y - tp.y) == 2) {
                //y
                return -1;
            }
        }
        return -2;
    }

    //计算棋子走的步数,起点到终点的步数
    public int getStep(Point tp) {
        int line = line(tp);
        if(line == 3) {
            //x
            return Math.abs(p.x - tp.x);
        }else if(line == 2 || line == 1) {
            //y,正斜线
            return Math.abs(p.y - tp.y);
        }

        return 0;
    }

    //判断象或马是否蹩脚,原理是判断蹩脚点是否存在棋子
    public boolean isBieJiao(Point tp,GamePanel gamePanel) {
        Point center = new Point();//中心点
        if("xiang".equals(name)) {
            //象
            center.x = (p.x + tp.x) / 2;
            center.y = (p.y + tp.y) / 2;
            //System.out.println(gamePanel.getChessByP(center));
            return gamePanel.getChessByP(center) != null;
        }else if("ma".equals(name)) {
        	//马
            int line = line(tp);
            if(line == 0) {
                //x
                center.x = (p.x + tp.x) / 2;
                center.y = p.y;
                return gamePanel.getChessByP(center) != null;
            }else if(line == -1) {
                //y
                center.y = (p.y + tp.y) / 2;
                center.x = p.x;
                return gamePanel.getChessByP(center) != null;
            }
        }
        return true;
    }

    //判断目标点是否过河
    public boolean isOverRiver(Point tp) {
        int upOrDown = isUpOrDown();
        if(upOrDown == 1) {
            //上
            if(tp.y < 6) {
                return false;
            }
        } else if (upOrDown == 2) {
            //下
            if(tp.y > 5) {
                return false;
            }
        }

        return true;
    }

    //判断棋子是否能移动到指定的位置
    public abstract boolean isAbleMove(Point tp,GamePanel gamePanel);

    //计算起点到目标点之间的棋子数量,不计算起点的棋子
    public int getCount(Point tp,GamePanel gamePanel) {
        int start = 0;
        int end = 0;
        int count = 0;//统计棋子数量
        int line = line(tp);
        Point np = new Point();
        if(line == 2)  {
            //y
            np.x = tp.x;
            if(tp.y > p.y) {
                //从上往下
                start = p.y + 1;
                end = tp.y;
            } else {
                //从下往上
                start = tp.y + 1;
                end = p.y;
            }
            for(int i = start; i < end; i++) {
                np.y = i;
                if(gamePanel.getChessByP(np) != null) {
                    count++;
                }
            }
        } else if (line == 3) {
            //x
            np.y = tp.y;
            if(tp.x > p.x) {
                //从左往右
                start = p.x + 1;
                end = tp.x;
            } else {
                //从右往左
                start = tp.x + 1;
                end = p.x;
            }
            for(int i = start; i < end; i++) {
                np.x = i;
                if(gamePanel.getChessByP(np) != null) {
                    count++;
                }
            }
        }
        return count;
    }

    //是否前进
    public boolean isForward(Point tp) {
        int upOrDown = isUpOrDown();
        if(upOrDown == 1) {
            //上
            if(tp.y > p.y) {
                return true;
            }
        } else if (upOrDown == 2) {
            //下
            if(tp.y < p.y) {
                return true;
            }
        }
        return false;
    }

    //是否后退
    public boolean isBack(Point tp) {
        int upOrDown = isUpOrDown();
        if(upOrDown == 1) {
            //上
            if(tp.y < p.y) {
                return true;
            }
        } else if (upOrDown == 2) {
            //下
            if(tp.y > p.y) {
                return true;
            }
        }
        return false;
    }
    //棋子的绘制方法
    public void draw(Graphics g, JPanel panel) {
        String path = "pic" + File.separator + name + player +suffix;
        Image img = Toolkit.getDefaultToolkit().getImage(path);
        g.drawImage(img,x,y,SIZE,SIZE,panel);
    }

    //为选中的棋子画一个边框
    public void drawRect(Graphics g) {
        g.drawRect(x,y,SIZE,SIZE);
    }

        //计算xy的绘制坐标
    public void calXY() {
        this.x = MARGIN - SIZE / 2 + SPACE * (p.x - 1);
        this.y = MARGIN - SIZE / 2 + SPACE * (p.y - 1);
    }

    public void setP(Point p) {
        this.p = (Point) p.clone();
        if(initP == null) {
            initP = this.p;
        }
        calXY();
    }

    public int getPlayer() {
        return player;
    }

    public Point getP() {
        return p;
    }

    //根据xy坐标计算网格坐标对象
    public static Point getPointFromXY(int x,int y) {
        Point p = new Point();
        p.x = (x - MARGIN + SIZE / 2) / SPACE + 1;
        p.y = (y - MARGIN + SIZE / 2) / SPACE + 1;
        if (p.x < 1 || p.x > 9 || p.y < 1 || p.y > 10) {
            return null;
        }
        return p;
    }
    //反转网格坐标
    public void reserve() {
        p.x = 10 - p.x;
        p.y = 11 - p.y;
        initP = p;
        calXY();
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPlayer(int player) {
        this.player = player;
    }

    public void Point(int x,int y) {
        this.x = x;
        this.y = y;
    }

    public Chess(String name, int player, Point p) {
        this.name = name;
        this.player = player;
        setP(p);
    }

    public Chess() {

    }
}

4.8 Ma

package com.code.main;

import java.awt.*;

public class Ma extends Chess{
    public Ma(int player,Point p) {
        super("ma",player,p);
    }

    public Ma(int player, int px) {
        this(player, new Point(px,1));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
            return (line(tp) == 0 || line(tp) == -1) && !isBieJiao(tp,gamePanel);
    }
}

4.9 Pao

package com.code.main;

import com.code.main.Chess;
import com.code.main.GamePanel;

import java.awt.*;

public class Pao extends Chess {
    public Pao(int player, Point p) {
        super("pao",player,p);
    }

    public Pao(int player, int px) {
        this(player, new Point(px,3));
    }
    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
        Chess c = gamePanel.getChessByP(tp);
            if(c != null) {
                //有棋子
                if(c.getPlayer() != this.player) {
                    //吃子
                    return line(tp) > 1 && getCount(tp, gamePanel) == 1;
                }
            } else {
                //移动
                return line(tp) > 1 && getCount(tp, gamePanel) == 0;
            }
            return false;
    }
}

4.10 Shi

package com.code.main;

import java.awt.*;

public class Shi extends Chess{
    public Shi(int player, Point p) {
        super("shi", player, p);
    }

    public Shi(int player, int px) {
        this(player, new Point(px,1));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
        return line(tp) == 1 && isHome(tp) && getStep(tp) == 1;
    }
}

4.11 Xiang

package com.code.main;

import java.awt.*;

public class Xiang extends Chess{
    public Xiang(int player, Point p) {
        super("xiang",player,p);
    }

    public Xiang(int player, int px) {
        this(player, new Point(px,1));
    }

    @Override
    public boolean isAbleMove(Point tp, GamePanel gamePanel) {
        return  line(tp) == 1 && getStep(tp) == 2 && !isBieJiao(tp,gamePanel) && !isOverRiver(tp);
    }
}


结语

本人水平有限,如有bug还请见谅

请给自己些耐心,一口吃不成胖子。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!


都看到这里啦!真棒(*^▽^*)

可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家

编程小白写作,如有纰漏或错误,欢迎指正


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/483214.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

‘str‘ object has no attribute ‘decode‘

跑别人代码的时候遇到一个问题 print(f"{gpu_device_name.decode(utf-8)} is allocated sucessfully at location: {gpu_device_location}")结果就报错了 解决问题如下 aa "adfd"aa.decode(utf-8)结果如下 aa "adfd" aa.encode().decode(ut…

初识进程的地址空间、页表

一、&#x1f31f;问题引入 &#x1f6a9;代码一&#xff1a; #include<stdio.h>#include<unistd.h>int g_val100;int main(){pid_t idfork();if(id0){//子进程while(1){printf("I am a child pid:%d ppid:%d g_val:%d\n",getpid(),getppid(),g_val);…

# Maven Bom 的使用

Maven Bom 的使用 文章目录 Maven Bom 的使用概述BOM特点优点缺点 MavenMaven 安装安装步骤settingx.ml常用仓库地址Idea 使用maven常见坑 SpringBoot 项目Bom使用案例项目结构主项目 zerocode-back-servezc-dependency&#xff08;第三方jar管理&#xff09;子模块zc-serve子模…

【保姆级教程】YOLOv8目标检测:训练自己的数据集

一、YOLOV8环境准备 1.1 下载安装最新的YOLOv8代码 仓库地址&#xff1a; https://github.com/ultralytics/ultralytics1.2 配置环境 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple二、数据准备 2.1 安装labelme标注软件 pip install label…

2024阿里云2核2G服务器租用价格99元和61元一年

阿里云2核2G服务器配置优惠价格61元一年和99元一年&#xff0c;61元是轻量应用服务器2核2G3M带宽、50G高效云盘&#xff1b;99元服务器是ECS云服务器经济型e实例ecs.e-c1m1.large&#xff0c;2核2G、3M固定带宽、40G ESSD entry系统盘&#xff0c;阿里云活动链接 aliyunfuwuqi.…

[STM32] Keil MDK 新建工程编译不通过(warning: #2803-D和Error: L6218E)解决方法备忘

按照野火的PDF教程的第4章&#xff1a;[野火]《RT-Thread 内核实现与应用开发实战—基于STM32》.pdf 新建 Keil MDK 工程&#xff0c;工程设置完成后点击编译按钮&#xff0c;编译不通过&#xff1a; RTE\Device\ARMCM3\startup_ARMCM3.c(75): warning: #2803-D: unrecognize…

JVM快速入门(1)JVM体系结构、运行时数据区、类加载器、线程共享和独享、分区、Java对象实例化

5.1 JVM体系结构 线程独占区-程序计数器&#xff08;Program Counter Register&#xff09; 程序计数器是一块较小的内存空间&#xff0c;它可以看做是当前线程所执行的字节码的行号指示器&#xff1b;在虚拟机的概念模型里&#xff0c;字节码解释器工作时就是通过改变这个计数…

C++:练习题

一、构造、析构顺序 C c; int main() {A a;B b;static D d;return 0; } //构造顺序&#xff1a;C A B D //析构顺序&#xff1a;~B ~A ~D ~C 二、拷贝构造次数 以下代码共调用多少次拷贝构造&#xff1f; Widget f(Widget u) //第一次&#xff1a;传值拷贝构造 {Widget v(u…

【QT+QGIS跨平台编译】之九十:【QGIS_Crashhandler+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、QGIS_Crashhandler介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、QGIS_Crashhandler介绍 QGIS_Crashhandler模块是QGIS中的一个重要组成部分,它提供了QGIS程序的错误崩溃处理与跟踪。 二、QGIS下载 QGIS网址: QGIS Source Download 获取最新版本的…

【Linux系统编程(进程编程)】进程的退出:父进程等待子进程的退出之僵尸进程与孤儿进程

文章目录 一、进程退出1.1、进程正常退出方式1.2、异常退出 二、父进程等待子进程退出&#xff08;一&#xff09;2.1、为什么要等待子进程退出2.2、&#xff08;1&#xff09;父进程等待子进程退出并收集子进程的退出状态如何等待wstatus空wstatus非空 2.3、&#xff08;2&…

数据背后的力量:揭秘中间件中的二分查找与树结构应用

平时写业务代码的时候很少写对应的算法&#xff0c;因为很少会在内存中存储大量数据&#xff0c;在需要比较大量数据的查找时&#xff0c;多会依赖的中间件&#xff0c;而中间件底层就应用了很多不同算法&#xff0c;尤其是树结构的查找存储算法&#xff0c;二分查找算法在树里…

状态管理@Prop、@Link装饰器

Prop Link 父子组件进行数据同步化 prop 单向同步 只支持string、number、boolean、enum类型 负组件对象类型&#xff0c;总组件是对象类型 不可以是数组、any 不允许子组件初始化 Link双向同步 父子类型一直&#xff1a;string、number、boolean、enum、object、class以及他们…

centos7 yum 安装mysql8.0.36

一、前置条件&#xff1a;CentOS Mini 安装需要先安装ifconfig 和 wget工具&#xff0c;参考步骤&#xff1a; 1.首先&#xff0c;让我们找出哪个包提供了ifconfig命令。要完成这项任务&#xff0c;输入以下命令&#xff1a; yum provides ifconfig 输出&#xff1a; [rootlo…

Vue3 + Django 前后端分离项目实现密码认证登录

1、功能需求 通常中小型前后端项目&#xff0c;对安全要求不高&#xff0c;也可以采用密码认证方案。如果只用django来实现非常简单。采用 Vue3 前后端分离架构&#xff0c;实现起来稍繁琐一点&#xff0c;好处是可以利用各种前端技术栈&#xff0c;如element-plus UI库来渲染…

Android Jetpack Compose基础之组件的帧渲染

Android Jetpack Compose基础之组件的帧渲染 组合布局LayoutModifier示例 LayoutCompsable示例 绘制CanvasDrawModifierDrawModifier-drawWithContent示例 DrawModifier-drawBehind源码示例 DrawModifier-drawWithCache源码示例 拓展Modifier.graphicsLayer Android View 系统&…

6-191 拓扑排序

一项工程由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其他子任务后才能执行。例如,下图表示了一项工程若干子任务之间的先后关系。 编写函数输出所有子任务的拓扑序列。 函数接口定义: Status Push_SeqStack(SeqStack &s, ElemType x)//入栈,x入到…

Polar 2024春季个人挑战赛 Jay17 WP

Polar 2024春季个人挑战赛 Rank&#xff1a;7 【WEB】机器人 开题 起手敏感文件robots.txt 【WEB】PHP反序列化初试 最简单的php反序列化 POC&#xff1a; <?php class Easy{public $name;public function __wakeup(){echo $this->name;} } class Evil{public $evi…

2、Jenkins持续集成-gitlab安装和源码上传

文章目录 1、Gitlab代码托管服务器安装2、源代码上传托管 环境&资源准备 统一采用VMware中安装CentOS7&#xff0c;安装教程&#xff0c;统一设置静态IP资源包都存在于我的资源里面 资源版本&位置 名称机器IP软件代码托管服务器192.168.2.100Gitlab-12.4.2持续集成服…

idm下载器 idm网络加速器 Internet Download Manager(IDM)免激活不弹窗版

idm下载器官方版英文名为Internet Download Manager。是一款界面简单、体积小巧下载速度飞快的下载工具&#xff0c;支持断点续传、多个任务同时下载&#xff0c;同时还支持限速下载&#xff0c;在自义文件类型里还可以自由设置下载的文件类型。 一、IDM软件安装 Internet Dow…

Linux安装Nginx及配置TCP负载均衡

目录 1、安装编译工具及库文件2、下载解压Nginx压缩包3、Ngnix配置Tcp负载均衡4、配置Ngnix的文件5、Nginx启动 1、安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel2、下载解压Nginx压缩包 wget https://nginx.o…