ADD file via upload

main
pibafzh6t 3 months ago
parent fddfe7fb75
commit f27ceb328a

@ -0,0 +1,655 @@
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
public class Sao_lei extends JFrame {
private JButton[] box_x; // 格子
private JMenuItem mo_shi_1, mo_shi_2, mo_shi_3, viewLeaderboard;
private String currentUsername = ""; // 当前用户名
private JPanel box_center;
private JLabel label_nadu; // 难度标签
private JLabel label_timer; // 计时标签
private int rows, cols; // 地图的行数和列数
private int lei; // 地雷数量
private int[][] mineMap; // 用于存储地图信息的二维数组
private Timer timer; // 计时器
private int timeall; // 经过的时间
private int flagsPlaced; // 已放置的标记数量
private ImageIcon face; // 笑脸图片
private JButton label_face; // 笑脸按钮
private LeaderboardDialog leaderboardDialog; // 排行榜对话框
private static class Mysql_Set {//静态类//只能有一个实类(无需创建类实类)//减少内存//直接通过类名调用//避免多线程安全//不会被修改//
private static final String URL = "jdbc:mysql://localhost:3306/saolei?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "254689";
public static void INIT_Mysql() {
try{
Class.forName("com.mysql.cj.jdbc.Driver");//链接驱动包JDBC
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);//建立连接
String SQL_txt = "CREATE TABLE IF NOT EXISTS leaderboard (" +//创建 表 如果 不 存在 leaderboard//
"id INT AUTO_INCREMENT PRIMARY KEY," +//id 整形 自增 主建(不能为NULL不能重复)//
"username VARCHAR(50) NOT NULL," +//username 字符串(50) 不能为空//
"time_used INT NOT NULL," +//time_used 整形 不能为空//
"difficulty VARCHAR(10) NOT NULL," +//difficulty 字符串(10) 不能为空//
"completion_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP" +//completion_time 时间戳T 默认当前时间DC//
")";//结束
Statement stmt = conn.createStatement();//创建一个对象
stmt.execute(SQL_txt);//执行SQL语句
} catch (SQLException | ClassNotFoundException e) {
JOptionPane.showMessageDialog(null, "数据库连接失败:", "错误", JOptionPane.ERROR_MESSAGE);//弹出错误信息框
}
}
public static void ADD_Mysql(String username, int timeUsed, String difficulty) {//插入用户数据
try {
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);//建立连接
String sql = "INSERT INTO leaderboard (username, time_used, difficulty) VALUES (?,?,?)";//插入 进入 排行榜 值(?占位符防止攻击)
PreparedStatement pstmt = conn.prepareStatement(sql);//创建一个对象
pstmt.setString(1, username);//设置占位符
pstmt.setInt(2, timeUsed);//设置占位符
pstmt.setString(3, difficulty);//设置占位符
pstmt.executeUpdate();//执行SQL语句
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "保存分数失败:" , "错误", JOptionPane.ERROR_MESSAGE);
}
}
public static List<ScoreRecord> GET_Mysql_Top(String difficulty, int limit) {//获取排行榜//返回泛型集合类型
List<ScoreRecord> scores = new ArrayList<>();//定义数组列表Scores
String sql = "SELECT username, time_used, completion_time FROM leaderboard " +//选择 123 来自 表//
"WHERE difficulty = ? ORDER BY time_used ASC LIMIT ?";//哪里 难度 = 从 表 排序 用时 从低到高 限制 //
try {
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);//建立连接
PreparedStatement pstmt = conn.prepareStatement(sql);//创建一个对象
pstmt.setString(1, difficulty);//设置占位符
pstmt.setInt(2, limit);//设置占位符
try (ResultSet rs = pstmt.executeQuery()) {//执行SQL语句
while (rs.next()) {
scores.add(new ScoreRecord(
rs.getString("username"),
rs.getInt("time_used"),
rs.getTimestamp("completion_time")
));
}
}
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "获取排行榜失败:" , "错误", JOptionPane.ERROR_MESSAGE);
}
return scores;
}
}
// 排行榜记录类
private static class ScoreRecord {
private String username;
private int timeUsed;
private Timestamp completionTime;
public ScoreRecord(String username, int timeUsed, Timestamp completionTime) {
this.username = username;
this.timeUsed = timeUsed;
this.completionTime = completionTime;
}
public String getUsername() {
return username;
}
public int getTimeUsed() {
return timeUsed;
}
public Timestamp getCompletionTime() {
return completionTime;
}
public String getFormattedTime() {
int minutes = timeUsed / 60;
int seconds = timeUsed % 60;
return String.format("%02d:%02d", minutes, seconds);
}
}
// 排行榜对话框类
private class LeaderboardDialog extends JDialog {
private JTable leaderboardTable;
private JComboBox<String> difficultyComboBox;
private DefaultTableModel tableModel;
private static final int MAX_SCORES = 10;
public LeaderboardDialog(JFrame parent) {
super(parent, "扫雷排行榜", true);
// 创建表格模型
String[] columnNames = {"排名", "用户名", "用时", "完成时间"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false; // 使表格不可编辑
}
};
// 创建表格
leaderboardTable = new JTable(tableModel);
leaderboardTable.getColumnModel().getColumn(0).setPreferredWidth(50);
leaderboardTable.getColumnModel().getColumn(1).setPreferredWidth(150);
leaderboardTable.getColumnModel().getColumn(2).setPreferredWidth(100);
leaderboardTable.getColumnModel().getColumn(3).setPreferredWidth(200);
// 创建难度选择下拉框
JPanel filterPanel = new JPanel();
filterPanel.add(new JLabel("难度:"));
difficultyComboBox = new JComboBox<>(new String[]{"简单", "普通", "困难"});
filterPanel.add(difficultyComboBox);
// 添加难度选择事件监听器
difficultyComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadLeaderboard((String) difficultyComboBox.getSelectedItem());
}
});
// 创建主面板
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(filterPanel, BorderLayout.NORTH);
mainPanel.add(new JScrollPane(leaderboardTable), BorderLayout.CENTER);
// 创建关闭按钮
JButton closeButton = new JButton("关闭");
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(closeButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
// 设置对话框属性
getContentPane().add(mainPanel);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(500, 400);
setLocationRelativeTo(parent);
// 加载默认难度的排行榜
loadLeaderboard("简单");
}
private void loadLeaderboard(String difficulty) {
// 清空表格
tableModel.setRowCount(0);
// 从数据库加载排行榜数据
List<ScoreRecord> scores = Mysql_Set.GET_Mysql_Top(difficulty, MAX_SCORES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 填充表格
for (int i = 0; i < scores.size(); i++) {
ScoreRecord score = scores.get(i);
tableModel.addRow(new Object[]{
i + 1,
score.getUsername(),
score.getFormattedTime(),
dateFormat.format(score.getCompletionTime())
});
}
}
public void showLeaderboard(String difficulty) {
difficultyComboBox.setSelectedItem(difficulty);
loadLeaderboard(difficulty);
setVisible(true);
}
}
// 登录对话框类
private class LoginDialog extends JDialog {
private JTextField usernameField;
private JButton loginButton;
private JButton cancelButton;
private boolean loggedIn = false;
private String username = "";
public LoginDialog(JFrame parent) {
super(parent, "登录", true);
// 创建面板
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
// 用户名标签
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
panel.add(new JLabel("用户名:"), gbc);
// 用户名输入框
usernameField = new JTextField(20);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(usernameField, gbc);
// 按钮面板
JPanel buttonPanel = new JPanel();
loginButton = new JButton("登录");
cancelButton = new JButton("取消");
buttonPanel.add(loginButton);
buttonPanel.add(cancelButton);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
panel.add(buttonPanel, gbc);
// 添加事件监听器
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (usernameField.getText().trim().isEmpty()) {
JOptionPane.showMessageDialog(LoginDialog.this,
"请输入用户名", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
username = usernameField.getText().trim();
loggedIn = true;
dispose();
}
});
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
});
// 按下Enter键时登录
usernameField.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
loginButton.doClick();
}
}
});
// 设置对话框属性
getContentPane().add(panel);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(parent);
setResizable(false);
}
public boolean isLoggedIn() {
return loggedIn;
}
public String getUsername() {
return username;
}
}
public Sao_lei() {
// 初始化数据库
Mysql_Set.INIT_Mysql();
// 显示登录对话框
LoginDialog loginDialog = new LoginDialog(this);
loginDialog.setVisible(true);
if (loginDialog.isLoggedIn()) {
currentUsername = loginDialog.getUsername();
} else {
// 如果用户取消登录,使用默认用户名
currentUsername = "玩家";
}
// 创建排行榜对话框
leaderboardDialog = new LeaderboardDialog(this);
//=====================================大窗口
JFrame boxmax = new JFrame("扫雷 - " + currentUsername);
boxmax.setSize(500, 600);
boxmax.setLayout(new BorderLayout()); // 布局为 BorderLayout
boxmax.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭操作
boxmax.setVisible(true); // 窗口可见
//====================================大窗口结束
//====================================顶部I
JMenuBar topmenu = new JMenuBar();
JMenu menu1 = new JMenu("开始游戏");
topmenu.add(menu1);
JMenu menu2 = new JMenu("难度选择");
topmenu.add(menu2);
JMenu menu3 = new JMenu("排行榜");
topmenu.add(menu3);
menu1.setFont(new Font("宋体", Font.PLAIN, 17));
menu2.setFont(new Font("宋体", Font.PLAIN, 17));
menu3.setFont(new Font("宋体", Font.PLAIN, 17));
mo_shi_1 = new JMenuItem("简单");
menu2.add(mo_shi_1);
mo_shi_2 = new JMenuItem("普通");
menu2.add(mo_shi_2);
mo_shi_3 = new JMenuItem("困难");
menu2.add(mo_shi_3);
viewLeaderboard = new JMenuItem("查看排行榜");
menu3.add(viewLeaderboard);
boxmax.setJMenuBar(topmenu);
//=====================================顶部I
//===========================================================顶部II
JPanel box_tops = new JPanel();
box_tops.setLayout(new BorderLayout());
label_nadu = new JLabel("难度:未选择(选择难度后开始游戏)");
box_tops.add(label_nadu, BorderLayout.WEST);
face = new ImageIcon("src/face.png");
face.setImage(face.getImage().getScaledInstance(50, 50, Image.SCALE_SMOOTH)); // 缩小笑脸按钮
label_face = new JButton(face);
label_face.setBounds(0, 0, 50, 50); // 设置按钮的大小与图片一致
label_face.setBorderPainted(false); // 不绘制边框
label_face.setContentAreaFilled(false); // 不填充按钮区域
label_face.setFocusPainted(false); // 不绘制焦点边框
box_tops.add(label_face, BorderLayout.CENTER);
label_timer = new JLabel("所用时间00:00");
box_tops.add(label_timer, BorderLayout.EAST);
boxmax.add(box_tops, BorderLayout.NORTH);
//===========================================================顶部II
//===========================================================中心区域
box_center = new JPanel();
JLabel game_text = new JLabel("<html>《基于Java的扫雷》<br><br><br>" +
"1. 先选择游戏难度<br>" +
"2. 点击笑脸重置游戏<br>" +
"3. 右键标记<br><br>" +
"制作人员:<br>" +
"🤵李&nbsp;钊231040600226<br>" +
"🤵梁诗超231040600227<br>" +
"👰刘芮臣231040600229<br></html>"); // 创建标签
game_text.setFont(new Font("宋体", Font.PLAIN, 25)); // 设置字体
game_text.setHorizontalAlignment(JLabel.CENTER); // 设置居中
box_center.add(game_text); // 添加到面板
boxmax.add(box_center, BorderLayout.CENTER);
//============================================================中心区域结束
//===========================================================监听
mo_shi_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
rows = 10;
cols = 10;
lei = 10;
mo_shi_main(rows, cols, lei);
label_nadu.setText("难度:简单");
}
});
mo_shi_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
rows = 16;
cols = 16;
lei = 40;
mo_shi_main(rows, cols, lei);
label_nadu.setText("难度:普通");
}
});
mo_shi_3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
rows = 20;
cols = 20;
lei = 80;
mo_shi_main(rows, cols, lei);
label_nadu.setText("难度:困难");
}
});
label_face.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 检查是否已选择难度
if (!checkDifficultySelected()) {
return;
}
timer.stop(); // 停止计时器
timeall = 0; // 重置计时器
Times(); // 更新计时器显示
mo_shi_main(rows, cols, lei); // 重新初始化游戏
face = new ImageIcon("src/face.png");
face.setImage(face.getImage().getScaledInstance(50, 50, Image.SCALE_SMOOTH)); // 缩小笑脸按钮
label_face.setIcon(face);
label_face.repaint(); // 重新绘制面板
}
});
// 排行榜菜单项监听器
viewLeaderboard.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 显示排行榜对话框
if (label_nadu.getText().contains("未选择")) {
leaderboardDialog.showLeaderboard("简单");
} else {
String difficulty = label_nadu.getText().substring(3);
leaderboardDialog.showLeaderboard(difficulty);
}
}
});
//=============================================================监听结束
//====================================================================计时器
timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
timeall++;
Times();
}
});
//====================================================================计时器结束
}
//==========================================================================模式函数
private void mo_shi_main(int rows, int cols, int lei) {
box_center.removeAll(); // 清除原有组件
box_center.setLayout(new GridLayout(rows, cols)); // 设置新的布局
box_x = new JButton[rows * cols]; // 创建按钮数组
mineMap = generateMinesweeperMap(rows, cols, lei); // 生成地图
flagsPlaced = 0; // 重置标记数量
for (int i = 0; i < rows * cols; i++) {
box_x[i] = new JButton("");
final int index = i; // 用于匿名类中访问
box_x[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
revealCell(index / cols, index % cols); // 点击时揭示格子
}
});
box_x[i].addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) { // 右键标记
markCell(index / cols, index % cols);
}
}
});
box_center.add(box_x[i]); // 添加到面板
}
box_center.revalidate(); // 重新验证布局
box_center.repaint(); // 重新绘制面板
timeall = 0; // 重置计时器
Times(); // 更新计时器显示
timer.start(); // 启动计时器
}
//==========================================================================模式函数结束
//=========================================================================================生成扫雷地图
private int[][] generateMinesweeperMap(int rows, int cols, int lei) {
int[][] map = new int[rows][cols];
Random random = new Random();
//1.定义二维数组,定义随机数生成器
//2.遍历总的雷的数量
//3.使用random.nextInt()方法随机生成0-rows-1的整数传给r作为行坐标
//4.使用random.nextInt()方法随机生成0-cols-1的整数穿给c作为列坐标
//5.判断二维数组中对应坐标的值是否为-1如果不是-1将其赋值为-1并将lei_num加1
int lei_num = 0;
while (lei_num < lei) {
int r = random.nextInt(rows);//随机生成0-rows-1的整数
int c = random.nextInt(cols);
if (map[r][c] != -1) {
map[r][c] = -1;
lei_num++;
}
}
//1.遍历总的行和列
//2.判断到此处不为雷
//3.定义一个变量lei_num_count记录周围雷的数量
//4.设置for循环-1到1的偏离值通过行列加减遍历周围8个格子
//5.跳过自身
//6.新的偏离值,固定在全局中,
//7.判断周围是否为雷如果是lei_num_count加1
//8.将lei_num_count赋值给二维数组对应坐标的值
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (map[r][c] != -1) {
int lei_num_count = 0;//记录周围雷的数量
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue; // 跳过自身
int newRow = r + i;
int newCol = c + j;
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && map[newRow][newCol] == -1) {
lei_num_count++;
}
}
}
map[r][c] = lei_num_count;
}
}
}
return map;
}
//========================================================================================生成扫雷地图结束
// 揭示格子
private void revealCell(int row, int col) {
if (row < 0 || row >= rows || col < 0 || col >= cols) return; // 超出范围
if (!box_x[row * cols + col].getText().isEmpty()) return; // 避免重复点击
if (mineMap[row][col] == -1) {
box_x[row * cols + col].setText("💥"); // 地雷
box_x[row * cols + col].setBackground(Color.RED);
timer.stop(); // 停止计时器
showGameOverDialog(); // 显示游戏结束对话框
} else {
box_x[row * cols + col].setText(String.valueOf(mineMap[row][col]));
box_x[row * cols + col].setEnabled(false);
if (mineMap[row][col] == 0) {
// 如果周围没有地雷,递归揭示周围格子
revealCell(row - 1, col);
revealCell(row + 1, col);
revealCell(row, col - 1);
revealCell(row, col + 1);
}
}
checkWinCondition(); // 检查是否胜利
}
// 标记格子
private void markCell(int row, int col) {
if (!box_x[row * cols + col].isEnabled()) return; // 已揭示的格子不能标记
if (box_x[row * cols + col].getText().isEmpty()) {
box_x[row * cols + col].setText("🚩"); // 放置标记
flagsPlaced++;
} else if (box_x[row * cols + col].getText().equals("🚩")) {
box_x[row * cols + col].setText(""); // 移除标记
flagsPlaced--;
}
checkWinCondition(); // 检查是否胜利
}
// 检查胜利条件
private void checkWinCondition() {
int revealedCells = 0; // 已揭示的非雷格子数量
int flaggedMines = 0; // 已标记的雷格子数量
for (int i = 0; i < rows * cols; i++) {
int row = i / cols;
int col = i % cols;
if (!box_x[i].isEnabled()) { // 格子已被揭示
if (mineMap[row][col] != -1) { // 非雷格子
revealedCells++;
}
} else if (box_x[i].getText().equals("🚩")) { // 格子已被标记
if (mineMap[row][col] == -1) { // 标记的格子是雷
flaggedMines++;
}
}
}
// 判断胜利条件
if (revealedCells == (rows * cols - lei) || flaggedMines == lei) {
timer.stop(); // 停止计时器
// 获取当前难度
String difficulty = label_nadu.getText().substring(3);
// 保存成绩到数据库
Mysql_Set.ADD_Mysql(currentUsername, timeall, difficulty);
// 显示胜利消息
JOptionPane.showMessageDialog(this,
"恭喜,你赢了!\n" +
"用户名:" + currentUsername + "\n" +
"难度:" + difficulty + "\n" +
"时间:" + label_timer.getText(),
"游戏胜利", JOptionPane.INFORMATION_MESSAGE);
// 显示排行榜
leaderboardDialog.showLeaderboard(difficulty);
}
}
// 显示游戏结束对话框
private void showGameOverDialog() {
JOptionPane.showMessageDialog(this,
"游戏结束!\n" +
"用户名:" + currentUsername + "\n" +
"难度:" + label_nadu.getText().substring(3) + "\n" +
"时间:" + label_timer.getText(),
"游戏结束", JOptionPane.INFORMATION_MESSAGE);
// 笑脸按钮换为苦脸
face = new ImageIcon("src/noface.png");
face.setImage(face.getImage().getScaledInstance(50, 50, Image.SCALE_SMOOTH)); // 缩小笑脸按钮
label_face.setIcon(face);
label_face.repaint(); // 重新绘制面板
}
// 检查是否已选择难度
private boolean checkDifficultySelected() {
if (label_nadu.getText().contains("未选择")) {
JOptionPane.showMessageDialog(this,
"请先选择游戏难度!",
"提示", JOptionPane.WARNING_MESSAGE);
return false;
}
return true;
}
// 更新计时器标签
private void Times() {
int minutes = timeall / 60;
int seconds = timeall % 60;
label_timer.setText(String.format("所用时间:%02d:%02d", minutes, seconds));
}
public static void main(String[] args) {
new Sao_lei();
}
}
Loading…
Cancel
Save