【Java進階學習 第八篇】石頭迷陣游戲

繪制頁面

首先繪制指定寬和高的窗體

        JFrame frame = new JFrame();frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);frame.setSize(514,595);frame.setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層frame.setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置frame.setLocationRelativeTo(null);frame.setVisible(true);

這里的窗體就是上一章的代碼,其中為了讓游戲一直在我們屏幕的最上層,使用了setAlwaysOnTop方法;并且想讓游戲開始時就在屏幕的居中位置,使用了setLocationRelativeTo方法。

效果:

繪制背景

圖像用JLabel里的ImageIcon添加就可以,那么是先添加石頭方塊還是先添加背景圖呢

應該是先添加石頭方塊,因為在同一重疊區域內,后添加的JLabel會放在圖層最底下

確定第一塊石頭的坐標(46,50)和大小(100,100);我們就可以添加所有的石頭方塊了,先手動添加

public class GameWidget {public static void main(String[] args) {JFrame frame = new JFrame();frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);frame.setSize(514,595);frame.setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層frame.setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置frame.setLocationRelativeTo(null);//取消默認布局frame.setLayout(null);//第一個方塊左邊是(50,90)JLabel label0 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\0.png"));label0.setBounds(50,90,100,100);frame.getContentPane().add(label0);JLabel label1 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\1.png"));label1.setBounds(150,90,100,100);frame.getContentPane().add(label1);JLabel label2 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\2.png"));label2.setBounds(250,90,100,100);frame.getContentPane().add(label2);JLabel label3 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\3.png"));label3.setBounds(350,90,100,100);frame.getContentPane().add(label3);JLabel label4 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\4.png"));label4.setBounds(50,190,100,100);frame.getContentPane().add(label4);JLabel label5 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\5.png"));label5.setBounds(150,190,100,100);frame.getContentPane().add(label5);JLabel label6 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\6.png"));label6.setBounds(250,190,100,100);frame.getContentPane().add(label6);JLabel label7 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\7.png"));label7.setBounds(350,190,100,100);frame.getContentPane().add(label7);JLabel label8 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\8.png"));label8.setBounds(50,290,100,100);frame.getContentPane().add(label8);JLabel label9 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\9.png"));label9.setBounds(150,290,100,100);frame.getContentPane().add(label9);JLabel label10 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\10.png"));label10.setBounds(250,290,100,100);frame.getContentPane().add(label10);JLabel label11 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\11.png"));label11.setBounds(350,290,100,100);frame.getContentPane().add(label11);JLabel label12 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\12.png"));label12.setBounds(50,390,100,100);frame.getContentPane().add(label12);JLabel label13= new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\13.png"));label13.setBounds(150,390,100,100);frame.getContentPane().add(label13);JLabel label14 = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\14.png"));label14.setBounds(250,390,100,100);frame.getContentPane().add(label14);JLabel label15= new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\15.png"));label15.setBounds(350,390,100,100);frame.getContentPane().add(label15);JLabel label = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));label.setBounds(26,30,450,484);frame.getContentPane().add(label);//設置窗口可見frame.setVisible(true);

?效果為

?


代碼優化

二維數組加循環嵌套

我們可以將圖像從0到15共16個數字作為二維數組的索引,0,1,2,3為第一行;這樣我們在后續調用圖像的時候,圖像路徑直接調用data[i][j]就可以了。

        JFrame frame = new JFrame();frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);frame.setSize(514,595);frame.setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層frame.setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置frame.setLocationRelativeTo(null);//取消默認布局frame.setLayout(null);//用二維數組記錄圖像的idint[][] data= {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}};for(int i=0;i<4;i++){for(int j=0;j<4;j++){//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\"+data[i][j]+".png"));imagelabel.setBounds(100*j+50,100*i+90,100,100);frame.getContentPane().add(imagelabel);}}//加背景圖像JLabel bglabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));bglabel.setBounds(26,30,450,484);frame.getContentPane().add(bglabel);//設置窗口可見frame.setVisible(true);

我們把行數看做i,列數看做j;可以看見我們每個方塊的坐標其實可以用j*100+50和i*100+50表示。


繼承優化

為了方便我們自己添加后續的功能,我們可以自己創建一個窗口類去繼承JFrame

public class MainFrame extends JFrame {}

?繼承好JFrame后,我們可以把之前的代碼粘貼過來,并且把所有關于窗體的代碼放在一個方法里面,所有繪制石頭的代碼放在一個方法里面

    public void paintStone(){for(int i=0;i<4;i++){for(int j=0;j<4;j++){//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\"+data[i][j]+".png"));imagelabel.setBounds(100*j+50,100*i+90,100,100);frame.getContentPane().add(imagelabel);}}//加背景圖像JLabel bglabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));bglabel.setBounds(26,30,450,484);frame.getContentPane().add(bglabel);}

這里我們會發現frame會報錯,但是不需要將其添加為成員變量;因為我們繼承了JFrame,JFrame類中的方法我們都有,所以我們可以將frame變成super,而且我們并沒有對父類JFrame中的方法進行重寫,所以super可以省略,最終兩個方法代碼為:

public class MainFrame extends JFrame {//用二維數組記錄圖像的idint[][] data= {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}};public void widgetInit(){setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);setSize(514,595);setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置setLocationRelativeTo(null);//取消默認布局setLayout(null);//設置窗口可見setVisible(true);}public void paintStone(){for(int i=0;i<4;i++){for(int j=0;j<4;j++){//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\"+data[i][j]+".png"));imagelabel.setBounds(100*j+50,100*i+90,100,100);getContentPane().add(imagelabel);}}//加背景圖像JLabel bglabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));bglabel.setBounds(26,30,450,484);getContentPane().add(bglabel);}

?我們希望兩個方法+窗口visible顯示在這個Mainframe創建對象的時候就顯示,那么我們可以寫入構造函數中

    public MainFrame() {widgetInit();paintStone();//設置窗口可見setVisible(true);}

我們在test文件中創建Mainframe的對象,進行測試,效果正常。


打亂石頭方塊

我們只需要對二維數組中的索引進行打亂就可以

使用random.nextInt(4)分別作為當前二維數組元素要交換的索引下標的行數和列數,遍歷一遍二維數組,進行交換就可以

    public void dataInit(){Random rand = new Random();for(int i=0;i<4;i++){for(int j=0;j<4;j++){int x=rand.nextInt(4);int y=rand.nextInt(4);int temp=data[x][y];data[x][y]=data[i][j];data[i][j]=temp;}}}

效果為


移動業務

首先要給我們的窗體增加鍵盤輸入上下左右的監聽

        //之前的鍵盤監聽格式是窗口對象frame.addKeyListener(KeyListener的實現類)//第一個this是代表本類MainFrame的對象//第二個this代表實現類KeyListener的對象this.addKeyListener(this);

像這段代碼中注釋所示,為了不讓我們的代碼更加繁瑣,我們可以用this(代表本類的對象)去分別代表窗體Mainframe類的對象以及實現類KeyListener的對象去加入鍵盤的監聽事件。

接下來系統會提示我們對實現類中的方法進行重寫,我們挑選KeyPressed方法進行重寫,并利用getKeyCode去調用我們要實現的移動業務方法move

    public void move(int keyCode){if (keyCode == 37) {System.out.println("左移動業務代碼執行");} else if (keyCode == 38) {System.out.println("上移動業務代碼執行");} else if (keyCode == 39) {System.out.println("右移動業務代碼執行");} else if (keyCode == 40) {System.out.println("下移動業務代碼執行");}}@Overridepublic void keyPressed(KeyEvent e) {//判斷鍵盤輸入是否為上下左右,對應移動業務int keyCode = e.getKeyCode();move(keyCode);}

?尋找零號元素

    public void dataInit(){Random rand = new Random();for(int i=0;i<4;i++){for(int j=0;j<4;j++){int x=rand.nextInt(4);int y=rand.nextInt(4);int temp=data[x][y];data[x][y]=data[i][j];data[i][j]=temp;}}//找到0號元素for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(data[i][j]==0){xindex=i;yindex=j;break;}}}}

這里的兩個零號元素需要作為成員變量,因為還有move方法要調用


進行判斷并移動位置

public class MainFrame extends JFrame implements KeyListener {public MainFrame() {//之前的鍵盤監聽格式是窗口對象frame.addKeyListener(KeyListener的實現類)//第一個this是代表本類MainFrame的對象//第二個this代表實現類KeyListener的對象this.addKeyListener(this);//初始化窗口widgetInit();//打亂石頭順序dataInit();//繪制石頭方塊paintStone();//設置窗口可見setVisible(true);}//記錄零號元素int xindex;int yindex;//用二維數組記錄圖像的idint[][] data= {{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}};public void dataInit(){Random rand = new Random();for(int i=0;i<4;i++){for(int j=0;j<4;j++){int x=rand.nextInt(4);int y=rand.nextInt(4);int temp=data[x][y];data[x][y]=data[i][j];data[i][j]=temp;}}//找到0號元素for(int i=0;i<4;i++){for(int j=0;j<4;j++){if(data[i][j]==0){xindex=i;yindex=j;break;}}}}public void widgetInit(){setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);setSize(514,595);setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置setLocationRelativeTo(null);//取消默認布局setLayout(null);}public void paintStone(){//為了刷新,我們要先清空之前的Label,要不然直接調用這個方法會放在圖層的最底下,不能顯示getContentPane().removeAll();for(int i=0;i<4;i++){for(int j=0;j<4;j++){//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\"+data[i][j]+".png"));imagelabel.setBounds(100*j+50,100*i+90,100,100);getContentPane().add(imagelabel);}}//加背景圖像JLabel bglabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));bglabel.setBounds(26,30,450,484);getContentPane().add(bglabel);//remove后需要repaint進行label的刷新getContentPane().repaint();}public void move(int keyCode){if (keyCode == 37) {//判斷是不是在最右邊,不是的話,右邊的石頭方塊就會向左移動if(yindex!=3){int temp=data[xindex][yindex];data[xindex][yindex]=data[xindex][yindex+1];data[xindex][yindex+1]=temp;yindex++;}System.out.println("左移動業務代碼執行");} else if (keyCode == 38) {if(xindex!=3){int temp=data[xindex][yindex];data[xindex][yindex]=data[xindex+1][yindex];data[xindex+1][yindex]=temp;xindex++;}System.out.println("上移動業務代碼執行");} else if (keyCode == 39) {if(yindex!=0){int temp=data[xindex][yindex];data[xindex][yindex]=data[xindex][yindex-1];data[xindex][yindex-1]=temp;yindex--;}System.out.println("右移動業務代碼執行");} else if (keyCode == 40) {if(xindex!=0){int temp=data[xindex][yindex];data[xindex][yindex]=data[xindex-1][yindex];data[xindex-1][yindex]=temp;xindex--;}System.out.println("下移動業務代碼執行");}}@Overridepublic void keyPressed(KeyEvent e) {//判斷鍵盤輸入是否為上下左右,對應移動業務int keyCode = e.getKeyCode();move(keyCode);//移動后需要刷新paintStone();}//--------------------------------------------------

假如說我們進行上移動操作,那么我們的空白格需要和下面的石頭格子進行交換位置,那就要判斷xindex是不是已經是3了,如果是3,那么就撞墻了,不能再進行交換了。

除此之外,我們每進行一次move操作,就需要刷新一下頁面。

繪制頁面方法需要先對之前的label進行removeall操作,再進行白板添加,再進行repaint進行刷新。?


游戲判定勝利

添加作弊器

當我的getKeyCode為90也就是鍵入z的時候,我希望能夠直接讓所有的石頭塊為正常狀態

        }else if (keyCode == 90) {data=new int[][]{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};}

判斷勝利winJudge方法?

    private boolean winJudge() {//將目前的data和windata進行對比for (int i=0;i<4;i++){for(int j=0;j<4;j++){if(data[i][j]!=windata[i][j]){return false;}}}//贏了就繪制勝利圖像,且應該結束游戲return true;}

我們先創建勝利狀態下的數組windata

    int[][] windata={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};

勝利狀態

我們現在需要在繪制頁面進行判斷,如果已經勝利了,加入勝利標志,而且不能再進行移動了

        //如果勝利,我們需要先加入勝利的Labelif(winJudge()){//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\win.png"));imagelabel.setBounds(124,230,266,88);getContentPane().add(imagelabel);//此時游戲已經勝利,不應該再移動了}
    public void move(int keyCode){//游戲勝利不能再移動了if(winJudge()){return;}

現在我們用作弊器測試一下效果

老鐵沒毛病?


統計步數

記錄一下我們用了多少步數,增加成員變量count。上下左右移動的時候都count++,最后在paint方法中加入我們的步數label

        //左上角加入步數JLabel footcount =new JLabel("目前已用步數:"+count);footcount.setBounds(50,20,100,20);getContentPane().add(footcount);

重新游戲

在paint方法中加入JButton,需要取消默認布局,取消焦點

點擊之后,我們需要重置步數,重置數據,重新繪制

        //添加按鈕JButton regamebtn =new JButton("重新開始");regamebtn.setBounds(350,20,100,20);getContentPane().add(regamebtn);regamebtn.setFocusable(false);//添加按鈕的點擊監聽regamebtn.addActionListener(this);

這里我們可以用內部匿名類,也可以再implements接口ActionListener去用this作為ActionListener的實現類對象,然后需要我們重寫方法,在重寫方法里面進行重置步數等命令

    @Overridepublic void actionPerformed(ActionEvent e) {//重置步數count=0;//重置data數據dataInit();//重新繪制paintStone();}

運行效果

全體代碼

package yuhan;import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;public class MainFrame extends JFrame implements KeyListener, ActionListener {public MainFrame() {//之前的鍵盤監聽格式是窗口對象frame.addKeyListener(KeyListener的實現類)//第一個this是代表本類MainFrame的對象//第二個this代表實現類KeyListener的對象this.addKeyListener(this);//初始化窗口widgetInit();//打亂石頭順序dataInit();//繪制石頭方塊paintStone();//設置窗口可見setVisible(true);}//記錄零號元素int xindex;int yindex;//統計步數int count;//用二維數組記錄圖像的idint[][] data = {{0, 1, 2, 3},{4, 5, 6, 7},{8, 9, 10, 11},{12, 13, 14, 15}};int[][] windata = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};public void dataInit() {Random rand = new Random();for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {int x = rand.nextInt(4);int y = rand.nextInt(4);int temp = data[x][y];data[x][y] = data[i][j];data[i][j] = temp;}}//找到0號元素for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (data[i][j] == 0) {xindex = i;yindex = j;return;}}}}public void widgetInit() {setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);setSize(514, 595);setTitle("石頭迷陣單機版v1.0");//想讓游戲一直在屏幕的最上層setAlwaysOnTop(true);//想讓窗體開始時在屏幕的居中位置setLocationRelativeTo(null);//取消默認布局setLayout(null);}public void paintStone() {//為了刷新,我們要先清空之前的Label,要不然直接調用這個方法會放在圖層的最底下,不能顯示getContentPane().removeAll();//左上角加入步數JLabel footcount = new JLabel("目前已用步數:" + count);footcount.setBounds(50, 20, 100, 20);getContentPane().add(footcount);//添加按鈕JButton regamebtn = new JButton("重新開始");regamebtn.setBounds(350, 20, 100, 20);getContentPane().add(regamebtn);regamebtn.setFocusable(false);//添加按鈕的點擊監聽regamebtn.addActionListener(this);//如果勝利,我們需要先加入勝利的Labelif (winJudge()) {//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\win.png"));imagelabel.setBounds(124, 230, 266, 88);getContentPane().add(imagelabel);//此時游戲已經勝利,不應該再移動了}for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {//第一個方塊左邊是(50,90)JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\" + data[i][j] + ".png"));imagelabel.setBounds(100 * j + 50, 100 * i + 90, 100, 100);getContentPane().add(imagelabel);}}//加背景圖像JLabel bglabel = new JLabel(new ImageIcon("D:\\Java資料\\資料\\進階篇\\day04\\資料\\image\\background.png"));bglabel.setBounds(26, 30, 450, 484);getContentPane().add(bglabel);//remove后需要repaint進行label的刷新getContentPane().repaint();}public void move(int keyCode) {//游戲勝利不能再移動了if (winJudge()) {return;}if (keyCode == 37) {//判斷是不是在最右邊,不是的話,右邊的石頭方塊就會向左移動if (yindex != 3) {int temp = data[xindex][yindex];data[xindex][yindex] = data[xindex][yindex + 1];data[xindex][yindex + 1] = temp;yindex++;count++;}System.out.println("左移動業務代碼執行");} else if (keyCode == 38) {if (xindex != 3) {int temp = data[xindex][yindex];data[xindex][yindex] = data[xindex + 1][yindex];data[xindex + 1][yindex] = temp;xindex++;count++;}System.out.println("上移動業務代碼執行");} else if (keyCode == 39) {if (yindex != 0) {int temp = data[xindex][yindex];data[xindex][yindex] = data[xindex][yindex - 1];data[xindex][yindex - 1] = temp;yindex--;count++;}System.out.println("右移動業務代碼執行");} else if (keyCode == 40) {if (xindex != 0) {int temp = data[xindex][yindex];data[xindex][yindex] = data[xindex - 1][yindex];data[xindex - 1][yindex] = temp;xindex--;count++;}System.out.println("下移動業務代碼執行");} else if (keyCode == 90) {data = new int[][]{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};}}@Overridepublic void keyPressed(KeyEvent e) {//判斷鍵盤輸入是否為上下左右,對應移動業務int keyCode = e.getKeyCode();move(keyCode);//移動后需要刷新paintStone();}private boolean winJudge() {//將目前的data和windata進行對比for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (data[i][j] != windata[i][j]) {return false;}}}//贏了就繪制勝利圖像,且應該結束游戲return true;}//--------------------------------------------------@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void actionPerformed(ActionEvent e) {//重置步數count = 0;//重置data數據dataInit();//重新繪制paintStone();}
}
package yuhan;public class test {public static void main(String[] args) {new MainFrame();}
}

?效果

至此,石頭迷陣游戲代碼編寫完畢,用了很多之前的類、接口、重寫方法、構造方法這些面向對象思想。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72313.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72313.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72313.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

wireguard搭配udp2raw部署內網

前言 上一篇寫了使用 wireguard 可以非常輕松的進行組網部署&#xff0c;但是如果服務器廠商屏蔽了 udp 端口&#xff0c;那就沒法了 針對 udp 被服務器廠商屏蔽的情況&#xff0c;需要使用一款 udp2raw 或 socat 類似的工具&#xff0c;來將 udp 打包成 tcp 進行通信 這里以…

Node.js REPL 深入解析

Node.js REPL 深入解析 引言 Node.js 作為一種流行的 JavaScript 運行環境,在服務器端開發中扮演著重要角色。REPL(Read-Eval-Print Loop,讀取-求值-打印循環)是 Node.js 的一個核心特性,它允許開發者在一個交互式環境中執行 JavaScript 代碼。本文將深入探討 Node.js R…

系統可觀測性(5)OpenTelemetry基礎使用

系統可觀測性(5)OpenTelemetry基礎概念 Author: Once Day Date: 2025年3月12日 一位熱衷于Linux學習和開發的菜鳥&#xff0c;試圖譜寫一場冒險之旅&#xff0c;也許終點只是一場白日夢… 漫漫長路&#xff0c;有人對你微笑過嘛… 本文檔翻譯整理自《OpenTelemetry Docs》&a…

AVL樹的平衡算法的簡化問題

AVL樹是一種緊湊的二叉查找樹。它的每個結點&#xff0c;都有左右子樹高度相等&#xff0c;或者只相差1這樣的特性。文章https://blog.csdn.net/aaasssdddd96/article/details/106291144給出了一個例子。 為了便于討論&#xff0c;這里對AVL樹的結點平衡情況定義2個名稱&#…

Jenkins 集成DingDing 推送

現狀分析 開發頻繁發布代碼&#xff0c;和測試沒有及時溝通&#xff0c;導致測試返工、bug漏測等 解決方案 Jenkins 集成DingDing機器人&#xff0c;在構建時觸發推送 DingDing端機器人配置 1、在釘釘電腦端建立群聊 2、點擊群右上角設置&#xff0c;點擊【智能群助手】 …

【Quarkus】通過Quarkus集成后端服務示例

說明&#xff1a; REST資源接口&#xff08;AuthResource&#xff09;。REST資源實現類&#xff08;AuthResourceImpl&#xff09;。服務接口&#xff08;AuthService&#xff09;。服務實現類&#xff08;AuthServiceImpl&#xff09;。配置文件&#xff08;application.prop…

硬件驅動——51單片機:獨立按鍵、中斷、定時器/計數器

目錄 一、獨立按鍵 1.原理 2.封裝函數 3.按鍵控制點燈 數碼管 二、中斷 1.原理 2.步驟 3.中斷寄存器IE 4.控制寄存器TCON 5.打開外部中斷0和1 三、定時器/計數器 1.原理 2.控制寄存器TCON 3.工作模式寄存器TMOD 4.按鍵控制頻率的動態閃爍 一、獨立按鍵 1…

基于PMU的14節點、30節點電力系統狀態估計MATLAB程序

“電氣仔推送”獲得資料&#xff08;專享優惠&#xff09; 程序簡介&#xff1a; 程序采用三種方法對14節點和30節點電力系統狀態進行評估&#xff1a; ①PMU同步向量測量單元結合加權最小二乘法&#xff08;WLS&#xff09;分析電力系統的電壓幅值和相角狀態&#xff1b; …

Apifox Helper 自動生成API接口文檔

在我們開發過程中我們在編寫請求地址和編寫請求參數的時候特別花費時間耗費了我們很多時間&#xff0c;作為一個程序員&#xff0c;更應該把精力時間集中在開發上&#xff0c; Apifox Helper 是 Apifox 團隊針對 IntelliJ IDEA 環境所推出的插件&#xff0c;可以在 IDEA 環境中…

Python 3.13實現數據未來預測功能(詳細功能實現及環境搭建)

目錄 摘要 1. 導入所需庫 2. 加載和查看數據 3. 數據預處理 4. 拆分數據集 5. 模型訓練 6. 模型評估 7. 進行預測 結論 摘要 本文將引導您使用Python 3.13實現數據預測功能。我們將使用常用的Python庫, 如pandas、numpy和sklearn&#xff0c;來幫助讀者快速搭建一個簡…

基于Redis實現限流的幾種方式

限流盡可能在滿足需求的情況下越簡單越好&#xff01; 分布式限流是指在分布式系統中對請求進行限制&#xff0c;以防止系統過載或濫用資源。以下是常見的分布式限流策略及其實現方式&#xff1a; 1、基于 Redis 的固定窗口限流 原理&#xff1a; 設定一個時間窗口&#xff0…

【前端文件下載實現:多種表格導出方案的技術解析】

前端文件下載實現&#xff1a;多種表格導出方案的技術解析 背景介紹 在企業級應用中&#xff0c;數據導出是一個常見需求&#xff0c;特別是表格數據的導出。在我們的管理系統中&#xff0c;不僅需要支持用戶數據的Excel導出&#xff0c;還需要處理多種格式的表格文件下載&am…

堆概念和結構

1. 二叉樹的順序結構 普通的二叉樹是不適合用數組來存儲的&#xff0c;因為可能會存在大量的空間浪費。而完全二叉樹更適合使用順序結構存儲。現實中通常 把堆使用順序結構的數組來存儲 &#xff0c;需要注意的是這里的堆和操作系統虛擬進程地址空間中的堆是兩回事&#xff0c…

VUE的腳手架搭建引入類庫

VUE的小白腳手架搭建 真的好久好久自己沒有發布自己博客了,對于一直在做后端開發的我 ,由于社會卷啊卷只好學習下怎么搭建前端,一起學習成長吧~哈哈哈(最終目的,能夠懂并簡易開發) 文章目錄 VUE的小白腳手架搭建1.下載node.js2.安裝vue腳手架3.創建一個項目4.代碼規范約束配置(…

使用 Arduino 和 ThingSpeak 通過互聯網進行實時溫度和濕度監測

使用 ThingSpeak 和 Arduino 通過 Internet 進行溫度和濕度監控 濕度和溫度是許多地方(如農場、溫室、醫療、工業家庭和辦公室)非常常見的測量參數。我們已經介紹了使用 Arduino 進行濕度和溫度測量,并在 LCD 上顯示數據。 在這個物聯網項目中,我們將使用ThingSpeak在互聯…

論文分享:PL-ALF框架實現無人機低紋理環境自主飛行

在室內倉庫、地下隧道等低紋理復雜場景中&#xff0c;無人機依賴視覺傳感器進行自主飛行時&#xff0c;往往會遇到定位精度低、路徑規劃不穩定等難題。針對這一問題&#xff0c;重慶郵電大學計算機學院雷大江教授團隊在IEEE Trans期刊上提出了一種新型自主飛行框架&#xff1a;…

[Java實戰]性能優化qps從1萬到3萬

一、問題背景 ? 事情起因是項目上springboot項目提供的tps達不到客戶要求,除了增加服務器提高tps之外,作為團隊的技術總監,架構師,技術扛把子,本著我不入地獄誰入地獄的原則,決心從代碼上優化,讓客戶享受到飛一般的感覺。雖然大多數編程工作在寫下第一行代碼時已經完成…

如何篩選能實現共享自助健身房“靈活性”的物聯網框架?

共享自助健身房已經成為一種新興的健身方式&#xff0c;這種模式方便快捷&#xff0c;尤其適合i人健身愛好者&#xff0c;市場接受度還是挺好的。對于無人自助式的健身房要想實現靈活性&#xff0c;要挑選什么樣的物聯網框架呢&#xff1f; 1. 支持多種通信協議 共享自助健身…

【后端】【django】拋棄 Django 自帶用戶管理后,能否使用 `simple-jwt`?

拋棄 Django 自帶用戶管理后&#xff0c;能否使用 simple-jwt&#xff1f; 一、結論 是的&#xff0c;即使拋棄了 Django 自帶的用戶管理&#xff08;AbstractUser 或 AbstractBaseUser&#xff09;&#xff0c;仍然可以使用 django-rest-framework-simplejwt&#xff08;簡稱…

【量化科普】Correlation,相關性

【量化科普】Correlation&#xff0c;相關性 &#x1f680;量化軟件開通 &#x1f680;量化實戰教程 在量化投資領域&#xff0c;相關性&#xff08;Correlation&#xff09;是一個核心概念&#xff0c;用于衡量兩個變量之間的線性關系強度和方向。簡單來說&#xff0c;它告…