帶權重的點名系統
案例要求
文件中有學生的信息,每個學生的信息獨占一行。包括學生的姓名,性別,權重
要求每次被抽中的學生,再次被抽中的概率在原先的基礎上降低一半。
本題的核心就是帶權重的隨機
分析?
權重,權重和,權重占比
如何將概率降低為原先的一半
假設總共10個人,一開始設定每個人的權重都是1,權重和是10,權重占比=權重/權重和,那么每個人的權重占比是0.1,說明每個人一開始被抽中的概率都是0.1,抽中后再次被抽中的概率在原先的基礎上降低一半,需要將其權重降低為原來的一半。修改完權重要將其寫回文件,下次再抽人時權重就是0.5了。
細節:
權重降低為原來的一半,權重和也會改變,但是改變很小(由10變為9.5),人數越多改變越小(假如一共100人時,權重和為100,抽到一人,這人權重降低為原來的一半,權重和由100變為99.5),可以視作不變,而這個人權重降低為原來的一半,權重和又視作不變,則權重占比就是原來的一半。被抽中的概率就是原先的一半
權重占比的區間范圍?
如何確定抽到哪個人
?一開始每個人的權重占比是0.1,說明可以將長度為1的數軸分為10等份,每個人占其中一份
這就是權重占比的區間范圍,例如:
????????于滄浪-男-1 (0.0~0.1]?
????????雙文楠-男-1 (0.1~0.2]
????????鞠弘杰-男-1 (0.2~0.3]
????????樂弘雪-男-1 (0.3~0.4]
????????貝澤瀚-男-1 (0.4~0.5]
????????孫秀逸-女-1 (0.5~0.6]
????????藺文思-女-1 (0.6~0.7]
????????燕芷靈-女-1 (0.7~0.8]
????????酆若環-女-1 (0.8~0.9]
????????廣飛瑤-女-1 (0.9~1.0]隨機一個0~1之間的數,其在哪個范圍就表示抽取到了哪個同學
代碼實現
Student類用于封裝文件中的數據
public class Student {private String name;private String sex;private double weight;public Student() {}public Student(String name, String sex, double weight) {this.name = name;this.sex = sex;this.weight = weight;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight = weight;}//toString方法數據格式與文件中相同//這樣直接傳遞學生對象的toString方法就能寫出相同格式的數據,public String toString() {return name + "-" + sex + "-" + weight;}
}
測試類?
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;public class Test2 {public static void main(String[] args) throws IOException {//定義集合存儲學生對象ArrayList<Student> list = new ArrayList<>();//將文件中的數據讀出,交給Student對象進行封裝BufferedReader br = new BufferedReader(new FileReader("day05\\names.txt"));String line;while ((line = br.readLine()) != null) {String[] arr = line.split("-");Student stu = new Student(arr[0], arr[1], Double.parseDouble(arr[2]));//將該Student添加到集合中list.add(stu);}br.close();//獲取總權重double weightSum = 0;for (Student stu : list) {weightSum = weightSum + stu.getWeight();}//計算每個人的權重占比,保存到一個數組中double[] arr = new double[list.size()];int index = 0;for (Student stu : list) {arr[index] = stu.getWeight() / weightSum;index++;}System.out.println(Arrays.toString(arr));//計算每個人權重占比的區間范圍//例如第一個人權重占比是0.1,那么就規定0~0.1是他的權重占比的區間范圍,記為0.1//0~0.1是第一個人的,那么第二個人的權重占比的區間范圍就從0.1開始//所以第二個人的權重占比的區間范圍是 第一個人權重占比~第一個人權重占比+自己的權重占比//依次往后//隨機一個0~1之間的數,若該數處于0~0.1,就表示隨機到了第一個人for (int i = 1; i < arr.length; i++) {//利用BigDecimal精確運算BigDecimal bd1 = BigDecimal.valueOf(arr[i - 1]);BigDecimal bd2 = BigDecimal.valueOf(arr[i]);arr[i] = bd1.add(bd2).doubleValue();}System.out.println(Arrays.toString(arr));//隨機0~1之間的數double random = Math.random();System.out.println(random);//判斷random在數組中的位置//數組中元素是有序的利用二分查找法//如果要查找的元素在數組中,返回該元素的索引//如果要查找的元素不在數組中,返回值 = -索引 -1//通過加法交換率得 索引= -(返回值 +1)int i = Arrays.binarySearch(arr, random);if (i >= 0) {System.out.println(i);} else {i = -i - 1;System.out.println(i);}//索引i表示抽到的人Student stu = list.get(i);System.out.println(stu);//修改這個人的權重為原來的一半stu.setWeight(stu.getWeight() / 2);//將修改后的數據寫回文件BufferedWriter bw = new BufferedWriter(new FileWriter("day05\\names.txt"));for (Student s : list) {bw.write(s.toString());bw.newLine();}bw.close();}
}
一開始文件中的數據? ? ? ? ?第一次抽取? ? ? ? ? ? ? ? ?第二次抽取? ? ? ? ? ? ? ? ?第三次抽取 ??
游戲注冊功能以及存檔功能
可以將用戶信息和游戲進度寫到一個文件中永久保存,這樣結束程序重新啟動時,數據不會丟失,借助IO將前面介紹的拼圖游戲完善
程序啟動類?
import java.io.IOException;public class App {public static void main(String[] args) throws IOException {//創建登錄界面,在登錄界面中成功登錄后創建游戲界面new LoginJFrame();}
}
登錄界面?
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;public class LoginJFrame extends JFrame implements MouseListener {//不止一個方法使用的變量定義在成員變量位置JButton login;JButton register;JTextField username;JTextField password;JTextField code;String codeStr;JLabel showCode;JDialog jDialog;//記錄所有用戶ArrayList<User> list = new ArrayList();//空參構造初始化登錄public LoginJFrame() throws IOException {//調用方法獲取文件中記錄的用戶信息,存儲在集合中UserInfo();//調用方法初始化登錄界面initFrame();//調用方法加載登錄界面圖式loadImages();//添加事件監聽,鼠標監聽事件MouseListenerlogin.addMouseListener(this);register.addMouseListener(this);showCode.addMouseListener(this);//設置界面可視,建議放在最后this.setVisible(true);}//定義方法獲取文件中記錄的用戶信息,存儲在集合中private void UserInfo() throws IOException {BufferedReader br = new BufferedReader(new FileReader("PuzzleGame\\UserInfo.txt"));String line;while ((line = br.readLine()) != null) {String[] arr = line.split("&");String username = arr[0].split("=")[1];String password = arr[1].split("=")[1];User u = new User(username, password);list.add(u);}br.close();}//定義方法加載登錄界面圖式private void loadImages() {//1. 添加用戶名文字JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\用戶名.png"));usernameText.setBounds(116, 135, 47, 17);this.getContentPane().add(usernameText);//2.添加用戶名輸入框username = new JTextField();username.setBounds(195, 134, 200, 30);this.getContentPane().add(username);//3.添加密碼文字JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\密碼.png"));passwordText.setBounds(130, 195, 32, 16);this.getContentPane().add(passwordText);//4.密碼輸入框password = new JTextField();password.setBounds(195, 195, 200, 30);this.getContentPane().add(password);//驗證碼提示JLabel codeText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\驗證碼.png"));codeText.setBounds(133, 256, 50, 30);this.getContentPane().add(codeText);//驗證碼的輸入框code = new JTextField();code.setBounds(195, 256, 100, 30);this.getContentPane().add(code);//調用工具類生成驗證碼codeStr = CodeUtil.getCode();//顯示生成的驗證碼showCode = new JLabel();//設置內容showCode.setText(codeStr);//位置和寬高showCode.setBounds(300, 256, 50, 30);//添加到界面this.getContentPane().add(showCode);//5.添加登錄按鈕login = new JButton();login.setBounds(123, 310, 128, 47);//設置按鈕背景圖login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登錄按鈕.png"));//去除按鈕的默認邊框login.setBorderPainted(false);//去除按鈕的默認背景login.setContentAreaFilled(false);this.getContentPane().add(login);//6.添加注冊按鈕register = new JButton();register.setBounds(256, 310, 128, 47);//設置按鈕背景圖register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注冊按鈕.png"));//去除按鈕的默認邊框register.setBorderPainted(false);//去除按鈕的默認背景register.setContentAreaFilled(false);this.getContentPane().add(register);//7.添加界面背景圖片JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\login\\background.png"));background.setBounds(0, 0, 470, 390);this.getContentPane().add(background);}//定義方法初始化登錄界面private void initFrame() {this.setSize(488, 430);this.setTitle("拼圖游戲登錄");this.setAlwaysOnTop(true);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(3);this.setLayout(null);}//定義方法判斷用戶名密碼是否正確private boolean checkUser(ArrayList<User> list, User u) {//查詢用戶名是否在集合中存在int index = checkUserName(list, u);if (index == -1) {//System.out.println("用戶名和密碼錯誤");return false;}//到這步,證明用戶名存在,判斷對應的密碼是否相同if (list.get(index).getPassWord().equals(u.getPassWord())) {//相同返回truereturn true;}//不同返回falsereturn false;}//定義方法查詢用戶名是否在集合中存在,存在返回索引,不存在返回-1private int checkUserName(ArrayList<User> list, User u) {for (int i = 0; i < list.size(); i++) {if (list.get(i).getUserName().equals(u.getUserName())) {return i;}}return -1;}//定義方法展示彈窗private void showDialog(String s) {jDialog = new JDialog();//設置彈框的寬和高:100,100jDialog.setSize(100, 100);//設置彈框居中jDialog.setLocationRelativeTo(null);//設置彈框置頂jDialog.setAlwaysOnTop(true);//設置關閉后進行其他操作jDialog.setModal(true);//創建一個JLabel去編寫文本內容JLabel textJlabel = new JLabel(s);textJlabel.setBounds(20, 50, 120, 60);//把文本JLabel添加到彈框當中jDialog.getContentPane().add(textJlabel);//把彈框展示出來jDialog.setVisible(true);}//鼠標監聽事件MouseListener//鼠標單擊調用該方法@Overridepublic void mouseClicked(MouseEvent e) {Object source = e.getSource();if (source == login) {//如果是登錄按鈕,獲取輸入框中的用戶名,密碼,驗證碼String myUserName = username.getText();String myPassWord = password.getText();String myCode = code.getText();//判斷是否為空,如果為空,提示:用戶名或密碼為空if (myUserName.equals("") || myPassWord.equals("")) {//展示彈框:用戶名或密碼為空//調用方法展示彈框,參數為需要展示的文字showDialog("用戶名或密碼為空");//換一個驗證碼codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判斷驗證碼是否正確if (!(myCode.equalsIgnoreCase(codeStr))) {//展示彈框:驗證碼錯誤showDialog("驗證碼錯誤");System.out.println("驗證碼錯誤");//換一個驗證碼codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判斷用戶名和密碼是否為正確,如果正確隱藏登錄界面,進入游戲界面。//調用方法判斷User myUser = new User(myUserName, myPassWord);boolean flag = checkUser(list, myUser);if (!flag) {//展示彈框:用戶名或密碼錯誤showDialog("用戶名或密碼錯誤");System.out.println("用戶名或密碼錯誤");//換一個驗證碼codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//到這步,證明用戶名和密碼正確//隱藏登錄界面,進入游戲界面this.setVisible(false);new GameJFrame();} else if (source == showCode) {//重新生成驗證碼codeStr = CodeUtil.getCode();showCode.setText(codeStr);} else if (source == register) {//進行注冊//關閉登錄界面this.setVisible(false);//創建注冊界面//把存儲用戶信息的集合傳遞過去,注冊時用戶名不能與集合中的重復new RegisterJFrame(list);}}//鼠標按下調用該方法@Overridepublic void mousePressed(MouseEvent e) {Object source = e.getSource();if (source == login) {//登錄按鈕//按下不松的時候利用setIcon方法,修改登錄按鈕的背景色login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登錄按下.png"));} else if (source == register) {//注冊按鈕//按下不松的時候利用setIcon方法,修改注冊按鈕的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注冊按下.png"));}}//鼠標釋放調用該方法@Overridepublic void mouseReleased(MouseEvent e) {Object source = e.getSource();//登錄按鈕//釋放的時候利用setIcon方法,恢復登錄按鈕的背景色if (source == login) {login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登錄按鈕.png"));} else if (source == register) {//注冊按鈕//釋放的時候利用setIcon方法,恢復注冊按鈕的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注冊按鈕.png"));}}//鼠標劃入調用該方法@Overridepublic void mouseEntered(MouseEvent e) {}//鼠標劃出調用該方法@Overridepublic void mouseExited(MouseEvent e) {}}
注冊界面
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;public class RegisterJFrame extends JFrame implements MouseListener {//存儲用戶集合ArrayList<User> list;//提升三個輸入框的變量的作用范圍,讓這三個變量可以在本類中所有方法里面可以使用。JTextField username = new JTextField();JTextField password = new JTextField();JTextField rePassword = new JTextField();//提升兩個按鈕變量的作用范圍,讓這兩個變量可以在本類中所有方法里面可以使用。JButton submit = new JButton();JButton reset = new JButton();//彈窗JDialog jDialog;public RegisterJFrame(ArrayList<User> list) {//接收傳遞過來的用戶集合this.list = list;//初始化界面initFrame();//調用方法加載登錄界面圖式initView();//添加事件監聽,鼠標監聽事件MouseListenersubmit.addMouseListener(this);reset.addMouseListener(this);//設置界面可視,建議放在最后this.setVisible(true);}//初始化界面private void initFrame() {//對自己的界面做一些設置。//設置寬高this.setSize(488, 430);//設置標題this.setTitle("拼圖游戲 V1.0注冊");//取消內部默認布局this.setLayout(null);//設置關閉模式this.setDefaultCloseOperation(3);//設置居中this.setLocationRelativeTo(null);//設置置頂this.setAlwaysOnTop(true);}//加載登錄界面圖式private void initView() {//添加注冊用戶名的文本JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\注冊用戶名.png"));usernameText.setBounds(85, 135, 80, 20);//添加注冊用戶名的輸入框username.setBounds(195, 134, 200, 30);//添加注冊密碼的文本JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\注冊密碼.png"));passwordText.setBounds(97, 193, 70, 20);//添加密碼輸入框password.setBounds(195, 195, 200, 30);//添加再次輸入密碼的文本JLabel rePasswordText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\再次輸入密碼.png"));rePasswordText.setBounds(64, 255, 95, 20);//添加再次輸入密碼的輸入框rePassword.setBounds(195, 255, 200, 30);//注冊的按鈕submit.setIcon(new ImageIcon("puzzlegame\\image\\register\\注冊按鈕.png"));submit.setBounds(123, 310, 128, 47);submit.setBorderPainted(false);submit.setContentAreaFilled(false);//重置的按鈕reset.setIcon(new ImageIcon("puzzlegame\\image\\register\\重置按鈕.png"));reset.setBounds(256, 310, 128, 47);reset.setBorderPainted(false);reset.setContentAreaFilled(false);//背景圖片JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\register\\background.png"));background.setBounds(0, 0, 470, 390);this.getContentPane().add(usernameText);this.getContentPane().add(passwordText);this.getContentPane().add(rePasswordText);this.getContentPane().add(username);this.getContentPane().add(password);this.getContentPane().add(rePassword);this.getContentPane().add(submit);this.getContentPane().add(reset);this.getContentPane().add(background);}//定義方法展示彈窗private void showDialog(String s) {jDialog = new JDialog();//設置彈框的寬和高:100,100jDialog.setSize(100, 100);//設置彈框居中jDialog.setLocationRelativeTo(null);//設置彈框置頂jDialog.setAlwaysOnTop(true);//設置關閉后進行其他操作jDialog.setModal(true);//創建一個JLabel去編寫文本內容JLabel textJlabel = new JLabel(s);textJlabel.setBounds(20, 50, 120, 60);//把文本JLabel添加到彈框當中jDialog.getContentPane().add(textJlabel);//把彈框展示出來jDialog.setVisible(true);}//鼠標單擊事件@Overridepublic void mouseClicked(MouseEvent e) {Object source = e.getSource();if (source == submit) {//注冊按鈕//得到三個輸入框中的數據String myUsername = username.getText();String myPassword = password.getText();String myRePassword = rePassword.getText();//三個輸入框中的數據不能為空if (myUsername.length() == 0 || myPassword.length() == 0 || myRePassword.length() == 0) {//彈窗提醒showDialog("輸入框不能為空");//結束方法return;}//密碼和再次輸入的密碼要相同if (!myPassword.equals(myRePassword)) {//彈窗提醒showDialog("兩次輸入的密碼不同");//結束方法return;}//用戶名要符合規定,4-16位大小寫字母和數字if (!myUsername.matches("[a-zA-Z0-9]{4,16}")) {//彈窗提醒showDialog("用戶名要4-16位大小寫字母和數字");//結束方法return;}//密碼要符合規定,至少6位大小寫字母和數字if (!myPassword.matches("[a-zA-Z0-9]{6,}")) {//彈窗提醒showDialog("密碼要至少6位大小寫字母和數字");//結束方法return;}//用戶名不能與集合中的重復//調用方法判斷if (containsUsername(myUsername)) {//彈窗提醒showDialog("用戶名已存在");//結束方法return;}//到這一步,說明用戶名和密碼符合條件//將其添加到用戶集合中,并寫到文件中永久存儲User u = new User(myUsername, myPassword);list.add(u);try {BufferedWriter bw = new BufferedWriter(new FileWriter("PuzzleGame\\UserInfo.txt"));for (User user : list) {bw.write(user.toString());bw.newLine();}bw.close();//開啟登錄界面this.setVisible(false);new LoginJFrame();} catch (IOException ex) {throw new RuntimeException(ex);}} else if (source == reset) {//重置按鈕//清空三個輸入框中的內容username.setText("");password.setText("");rePassword.setText("");}}//判斷自定義用戶名是否與集合中的用戶名重復private boolean containsUsername(String myUsername) {for (User u : list) {if (u.getUserName().equals(myUsername)) {return true;}}return false;}//鼠標按下事件@Overridepublic void mousePressed(MouseEvent e) {Object source = e.getSource();//切換按鈕深色背景if (source == submit) {submit.setIcon(new ImageIcon("PuzzleGame\\image\\register\\注冊按下.png"));} else if (source == reset) {reset.setIcon(new ImageIcon("PuzzleGame\\image\\register\\重置按下.png"));}}//鼠標釋放事件@Overridepublic void mouseReleased(MouseEvent e) {Object source = e.getSource();//切換按鈕正常背景if (source == submit) {submit.setIcon(new ImageIcon("PuzzleGame\\image\\register\\注冊按鈕.png"));} else if (source == reset) {reset.setIcon(new ImageIcon("PuzzleGame\\image\\register\\重置按鈕.png"));}}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}
}
游戲界面
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.Random;//游戲界面類繼承界面類,實現鍵盤監聽和動作監聽
public class GameJFrame extends JFrame implements KeyListener, ActionListener {//多個方法需要用到的變量,記錄在成員變量的位置//定義二維數組記錄打亂后的0~15,每一個數字對應一張拼圖int[][] data = new int[4][4];//定義勝利時的數據數組int[][] winArr = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};//定義坐標記錄0的位置int x = 0;int y = 0;//定義計數器記錄移動步數int stepCount = 0;//創建菜單選項里下面的條目JMenuItem restartItem = new JMenuItem("重新開始");JMenuItem reLoginItem = new JMenuItem("重新登錄");JMenuItem exitItem = new JMenuItem("退出游戲");JMenuItem animalItem = new JMenuItem("動物");JMenuItem girllItem = new JMenuItem("美女");JMenuItem sportItem = new JMenuItem("運動");JMenuItem AccountItem = new JMenuItem("公眾號");JMenu saveJmenu = new JMenu("存檔");JMenuItem saveItem0 = new JMenuItem("存檔0(空)");JMenuItem saveItem1 = new JMenuItem("存檔1(空)");JMenuItem saveItem2 = new JMenuItem("存檔2(空)");JMenu loadJmenu = new JMenu("讀檔");JMenuItem loadItem0 = new JMenuItem("讀檔0(空)");JMenuItem loadItem1 = new JMenuItem("讀檔1(空)");JMenuItem loadItem2 = new JMenuItem("讀檔2(空)");//定義圖片路徑,方便后面修改String path = "PuzzleGame\\image\\animal\\animal1\\";Random r = new Random();//空參構造初始化游戲public GameJFrame() {//調用方法初始化界面initFrame();//給界面添加事件監聽,鍵盤監聽KeyListenerthis.addKeyListener(this);//調用方法添加菜單initMenu();//給菜單里的條目添加事件監聽,動作監聽ActionListenerrestartItem.addActionListener(this);reLoginItem.addActionListener(this);exitItem.addActionListener(this);AccountItem.addActionListener(this);animalItem.addActionListener(this);girllItem.addActionListener(this);sportItem.addActionListener(this);saveItem0.addActionListener(this);saveItem1.addActionListener(this);saveItem2.addActionListener(this);loadItem0.addActionListener(this);loadItem1.addActionListener(this);loadItem2.addActionListener(this);//調用方法初始化數據initData();//調用方法根據初始化后的數據加載圖片loadImages();//設置界面可視,建議放在最后this.setVisible(true);}//定義方法判斷游戲是否勝利private boolean victoty() {for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (data[i][j] != winArr[i][j]) {//data中的數據有一個與勝利數組中的數據不同,就說明沒有勝利return false;}}}return true;}//定義方法根據初始化后的數據加載圖片private void loadImages() {//清空所有圖片this.getContentPane().removeAll();//如果勝利,加載勝利圖標if (victoty()) {JLabel vicJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\win.png"));vicJLabel.setBounds(203, 283, 197, 73);this.getContentPane().add(vicJLabel);}//加載計數器JLabel countJLabel = new JLabel("步數:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//利用循環加載拼圖圖片for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//獲得data數組里的數據int number = data[i][j];//根據數據創建圖片對象ImageIcon icon = new ImageIcon(path + number + ".jpg");//創建管理容器,將圖片交給管理容器JLabel jLabel = new JLabel(icon);//設置管理容器位置,大小jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);//設置邊框jLabel.setBorder(new BevelBorder(0));//將管理容器添加到界面中this.getContentPane().add(jLabel);}}//添加背景圖片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}//定義方法初始化數據private void initData() {int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};//打亂數據,根據打亂后的數據就能實現打亂拼圖for (int i = 0; i < tempArr.length; i++) {int index = r.nextInt(tempArr.length);int temp = tempArr[i];tempArr[i] = tempArr[index];tempArr[index] = temp;}//將打亂后的數據記錄在二維數組data中for (int i = 0; i < tempArr.length; i++) {//如果是0,記錄0的位置if (tempArr[i] == 0) {x = i / 4;y = i % 4;}data[i / 4][i % 4] = tempArr[i];}}//定義方法添加菜單private void initMenu() {//創建菜單JMenuBar jMenuBar = new JMenuBar();//創建菜單的選項JMenu functionJmenu = new JMenu("功能");JMenu aboutJmenu = new JMenu("關于我們");//嵌套二級菜單,JMenu里面是可以再次添加其他的JMenuJMenu updateJmenu = new JMenu("更換圖片");updateJmenu.add(animalItem);updateJmenu.add(girllItem);updateJmenu.add(sportItem);//存檔saveJmenu.add(saveItem0);saveJmenu.add(saveItem1);saveJmenu.add(saveItem2);//讀檔loadJmenu.add(loadItem0);loadJmenu.add(loadItem1);loadJmenu.add(loadItem2);//將條目添加到選項中functionJmenu.add(updateJmenu);functionJmenu.add(restartItem);functionJmenu.add(reLoginItem);functionJmenu.add(exitItem);functionJmenu.add(saveJmenu);functionJmenu.add(loadJmenu);aboutJmenu.add(AccountItem);//將選項添加到菜單中jMenuBar.add(functionJmenu);jMenuBar.add(aboutJmenu);//將菜單添加到界面中this.setJMenuBar(jMenuBar);//游戲開始時獲取游戲數據信息修改菜單提示getGameInfo();}//游戲開始時獲取游戲數據信息修改菜單提示private void getGameInfo() {//遍歷存檔文件夾File f = new File("PuzzleGame\\save");File[] files = f.listFiles();if (files == null) {return;}for (File file : files) {//讀取每一個文件信息GameInfo gi = null;try {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));gi = (GameInfo) ois.readObject();ois.close();} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}//獲取要體現在菜單上的步數信息int step = gi.getStepCount();//獲取要修改的條目索引String name = file.getName();//save0/1/2.dataint index = name.charAt(4) - '0';//進行修改JMenuItem item1 = saveJmenu.getItem(index);item1.setText("存檔" + index + "(" + step + "步)");JMenuItem item2 = loadJmenu.getItem(index);item2.setText("讀檔" + index + "(" + step + "步)");}}//定義方法初始化界面private void initFrame() {//設置大小this.setSize(603, 680);//設置標題this.setTitle("拼圖游戲");//設置居中this.setLocationRelativeTo(null);//設置置頂this.setAlwaysOnTop(true);//設置關閉模式this.setDefaultCloseOperation(3);//設置解除默認居中放置,只有解除了,才能根據xy軸的方式添加主件this.setLayout(null);}//動作監聽ActionListener,鼠標單擊或按空格調用該方法@Overridepublic void actionPerformed(ActionEvent e) {Object source = e.getSource();if (source == restartItem) {//重新開始//重新初始化數據initData();//計數器歸0stepCount = 0;//重新根據初始化后的數據加載圖片loadImages();} else if (source == reLoginItem) {//重新登錄//關閉本類(游戲類)this.setVisible(false);//創建登錄界面try {new LoginJFrame();} catch (IOException ex) {throw new RuntimeException(ex);}} else if (source == exitItem) {//退出游戲System.exit(0);} else if (source == AccountItem) {//顯示公眾號//創建彈窗JDialog accJDialog = new JDialog();//加載彈窗中的圖片JLabel aboutJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\about.png"));aboutJLabel.setBounds(0, 0, 258, 258);//將圖片添加到彈窗中accJDialog.getContentPane().add(aboutJLabel);//設置彈窗的大小accJDialog.setSize(344, 344);//設置彈窗置頂accJDialog.setAlwaysOnTop(true);//設置彈窗居中放置accJDialog.setLocationRelativeTo(null);//設置關閉后進行其他操作accJDialog.setModal(true);//設置彈窗可視accJDialog.setVisible(true);} else if (source == animalItem) {//隨機更換動物圖片int rAnimalNum = r.nextInt(8) + 1;path = "PuzzleGame\\image\\animal\\animal" + rAnimalNum + "\\";//重新初始化數據initData();//計數器歸0stepCount = 0;//重新根據初始化后的數據加載圖片loadImages();} else if (source == girllItem) {//隨機更換美女圖片int rGirlNum = r.nextInt(13) + 1;path = "PuzzleGame\\image\\girl\\girl" + rGirlNum + "\\";//重新初始化數據initData();//計數器歸0stepCount = 0;//重新根據初始化后的數據加載圖片loadImages();} else if (source == sportItem) {//隨機更換運動圖片int rSportlNum = r.nextInt(10) + 1;path = "PuzzleGame\\image\\sport\\sport" + rSportlNum + "\\";//重新初始化數據initData();//計數器歸0stepCount = 0;//重新根據初始化后的數據加載圖片loadImages();} else if (source == saveItem0 || source == saveItem1 || source == saveItem2) {//進行存檔//得到點擊的存檔序號JMenuItem item = (JMenuItem) source;String text = item.getText();//存檔0/1/2(空)int index = text.charAt(2) - '0';//封裝要保存的游戲數據//包括:對應拼圖的data數組,記錄0位置的坐標x,y,圖片路徑path,步數stepCountGameInfo gi = new GameInfo(data, x, y, stepCount, path);//將游戲信息對象以序列化流寫入對應文件中,防止篡改數據try {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("PuzzleGame\\save\\save" + index + ".data"));oos.writeObject(gi);oos.close();} catch (IOException ex) {throw new RuntimeException(ex);}//修改菜單上的提示信息item.setText("存檔" + index + "(" + stepCount + "步)");//獲取與存檔對應的讀檔菜單JMenuItem item1 = loadJmenu.getItem(index);item1.setText("讀檔" + index + "(" + stepCount + "步)");} else if (source == loadItem0 || source == loadItem1 || source == loadItem2) {//進行讀檔//得到點擊的讀檔序號JMenuItem item = (JMenuItem) source;String text = item.getText();//讀檔0/1/2(空)int index = text.charAt(2) - '0';//利用反序列化流讀取文件中的游戲數據GameInfo gi = null;try {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PuzzleGame\\save\\save" + index + ".data"));gi = (GameInfo) ois.readObject();ois.close();} catch (IOException ex) {throw new RuntimeException(ex);} catch (ClassNotFoundException ex) {throw new RuntimeException(ex);}//將游戲數據更新為存檔的游戲數據data = gi.getData();x = gi.getX();y = gi.getY();path = gi.getPath();stepCount = gi.getStepCount();//重新加載游戲loadImages();}}//鍵盤監聽KeyListener//該方法基本不使用@Overridepublic void keyTyped(KeyEvent e) {}//長按鍵盤時調用該方法@Overridepublic void keyPressed(KeyEvent e) {//判斷是否勝利if (victoty()) {//如果勝利,禁止進行顯示全圖操作,直接結束方法return;}//長按w顯示全圖int keyCode = e.getKeyCode();if (keyCode == 87) {//清空所有圖片this.getContentPane().removeAll();//加載計數器JLabel countJLabel = new JLabel("步數:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//加載全圖JLabel picJLabel = new JLabel(new ImageIcon(path + "all.jpg"));picJLabel.setBounds(83, 134, 420, 420);this.getContentPane().add(picJLabel);//添加背景圖片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}}//按下并松開鍵盤時調用該方法@Overridepublic void keyReleased(KeyEvent e) {//判斷是否勝利if (victoty()) {//如果勝利,禁止進行移動操作,直接結束方法return;}int keyCode = e.getKeyCode();if (keyCode == 37) {//判斷是否到了最左邊if (y == 0) {//如果到了最左邊,不能進行向左,直接結束方法return;}//沒到最左邊,進行下面的操作System.out.println("向左");//更改data數組里的數據data[x][y] = data[x][y - 1];data[x][y - 1] = 0;//更改0的坐標y--;//步數加1stepCount++;//按照此數據重新加載圖片loadImages();} else if (keyCode == 38) {//判斷是否到了最上邊if (x == 0) {//如果到了最上邊,不能進行向上,直接結束方法return;}//沒到最上邊,進行下面的操作System.out.println("向上");//更改data數組里的數據data[x][y] = data[x - 1][y];data[x - 1][y] = 0;//更改0的坐標x--;//步數加1stepCount++;//按照此數據重新加載圖片loadImages();} else if (keyCode == 39) {//判斷是否到了最右邊if (y == 3) {//如果到了最右邊,不能進行向右,直接結束方法return;}//沒到最右邊,進行下面的操作System.out.println("向右");//更改data數組里的數據data[x][y] = data[x][y + 1];data[x][y + 1] = 0;//更改0的坐標y++;//步數加1stepCount++;//按照此數據重新加載圖片loadImages();} else if (keyCode == 40) {//判斷是否到了最下邊if (x == 3) {//如果到了最下邊,不能進行向下,直接結束方法return;}//沒到最下邊,進行下面的操作System.out.println("向下");//更改data數組里的數據data[x][y] = data[x + 1][y];data[x + 1][y] = 0;//更改0的坐標x++;//步數加1stepCount++;//按照此數據重新加載圖片loadImages();} else if (keyCode == 87) {//松開w恢復原狀loadImages();} else if (keyCode == 65) {//一鍵通過for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {data[i][j] = winArr[i][j];}}loadImages();}}}
?封裝用戶信息
public class User {private String userName;private String passWord;public User() {}public User(String userName, String passWord) {this.userName = userName;this.passWord = passWord;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}@Overridepublic String toString() {return "uesrname="+userName+"&password="+passWord;}
}
封裝游戲信息
import java.io.Serial;
import java.io.Serializable;public class GameInfo implements Serializable {@Serialprivate static final long serialVersionUID = 3545018877843048289L;private int[][] data;private int x;private int y;private int stepCount;private String path;public GameInfo() {}public GameInfo(int[][] data, int x, int y, int stepCount, String path) {this.data = data;this.x = x;this.y = y;this.stepCount = stepCount;this.path = path;}public int[][] getData() {return data;}public void setData(int[][] data) {this.data = data;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getStepCount() {return stepCount;}public void setStepCount(int stepCount) {this.stepCount = stepCount;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String toString() {return "GameInfo{data = " + data + ", x = " + x + ", y = " + y + ", stepCount = " + stepCount + ", path = " + path + "}";}
}
生成驗證碼工具類
import java.util.Random;public class CodeUtil {private CodeUtil(){}public static String getCode(){//定義StringBuilder方便拼接字符串StringBuilder sb = new StringBuilder();//記錄a~z,A~Zchar[] ch = new char[52];for (int i = 0; i < ch.length; i++) {if (i < 26) {ch[i] = (char) ('a' + i);} else {ch[i] = (char) ('A' + i - 26);}}Random r = new Random();//隨機抽取4個字母for (int i = 0; i < 4; i++) {int index = r.nextInt(ch.length);char randomCh = ch[index];//拼接sb.append(randomCh);}//隨機抽取1個字母int randomNum = r.nextInt(10);//拼接sb.append(randomNum);//數字可以位于隨機位置,因此最后一位需要與隨機位置交換char[] chars = sb.toString().toCharArray();int index = r.nextInt(chars.length);char temp = chars[chars.length-1];chars[chars.length-1] = chars[index];chars[index] = temp;return new String(chars);}}