javasweeper/Main.java

257 lines
8.6 KiB
Java
Raw Normal View History

2023-05-21 15:13:45 -07:00
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.util.stream.Stream;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.event.*;
public class Main {
public static final String DEFAULT_SKIN = "winxpskin.bmp";
public static final String SKINS_DIR = "Skins/";
public static final String HELP_FILE = "help.html";
public static final String ABOUT_FILE = "about.html";
private static final String[] VALID_EXTENSIONS = {".bmp", ".png", ".webp"};
private static final JFrame FRAME = new JFrame("Minesweeper");
private static Canvas canvas;
private static String skin;
public static void main(String[] args) {
skin = DEFAULT_SKIN;
FRAME.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FRAME.setResizable(false);
FRAME.setJMenuBar(getMenuBar());
2023-05-24 17:34:20 -07:00
setCanvas();
2023-05-21 15:13:45 -07:00
2023-05-24 17:34:20 -07:00
FRAME.setVisible(true);
2023-05-21 15:13:45 -07:00
}
private static JMenuBar getMenuBar() {
2023-05-24 17:34:20 -07:00
// Button group for the difficulty buttons
ButtonGroup difficultyButtons = new ButtonGroup();
Difficulty difficulty = Options.getDifficulty();
JRadioButtonMenuItem beginnerItem = new JRadioButtonMenuItem("Beginner",
difficulty == Difficulty.BEGINNER);
JRadioButtonMenuItem intermediateItem = new JRadioButtonMenuItem("Intermediate",
difficulty == Difficulty.INTERMEDIATE);
JRadioButtonMenuItem expertItem = new JRadioButtonMenuItem("Expert",
difficulty == Difficulty.EXPERT);
JRadioButtonMenuItem customItem = new JRadioButtonMenuItem("Custom...");
difficultyButtons.add(beginnerItem);
difficultyButtons.add(intermediateItem);
difficultyButtons.add(expertItem);
difficultyButtons.add(customItem);
2023-05-21 15:13:45 -07:00
ActionListener listener = new ActionListener() {
2023-05-24 17:34:20 -07:00
// Keep track of the previously selected difficulty button in case a
// Custom press is canceled so we can revert back to whatever it was
// before
private ButtonModel lastDifficultyButton = difficultyButtons.getSelection();
2023-05-21 15:13:45 -07:00
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "new":
canvas.restart();
break;
case "beginner":
setDifficulty(Difficulty.BEGINNER);
2023-05-24 17:34:20 -07:00
lastDifficultyButton = beginnerItem.getModel();
2023-05-21 15:13:45 -07:00
break;
case "intermediate":
setDifficulty(Difficulty.INTERMEDIATE);
2023-05-24 17:34:20 -07:00
lastDifficultyButton = intermediateItem.getModel();
2023-05-21 15:13:45 -07:00
break;
case "expert":
setDifficulty(Difficulty.EXPERT);
2023-05-24 17:34:20 -07:00
lastDifficultyButton = expertItem.getModel();
2023-05-21 15:13:45 -07:00
break;
case "custom":
2023-05-24 17:34:20 -07:00
if (Difficulty.setCustom(FRAME)) {
setDifficulty(Difficulty.CUSTOM);
lastDifficultyButton = customItem.getModel();
} else {
lastDifficultyButton.setSelected(true);
}
2023-05-21 15:13:45 -07:00
break;
case "protectedstart":
2023-05-24 17:34:20 -07:00
Options.toggleProtectedStart();
2023-05-21 15:13:45 -07:00
break;
case "sound":
2023-05-24 17:34:20 -07:00
Options.toggleSound();
2023-05-21 15:13:45 -07:00
Sound.initSounds();
break;
case "exit":
FRAME.dispatchEvent(new WindowEvent(FRAME, WindowEvent.WINDOW_CLOSING));
break;
case "help":
messageHtmlFile(HELP_FILE, "Failed to read help file, just google it lol.",
"Minesweeper Help", JOptionPane.QUESTION_MESSAGE);
break;
case "about":
messageHtmlFile(ABOUT_FILE, "I love microsoft!!",
"Minesweeper About", JOptionPane.INFORMATION_MESSAGE);
break;
}
}
};
JMenuBar menuBar = new JMenuBar();
JMenu gameMenu = new JMenu("Game");
gameMenu.setMnemonic(KeyEvent.VK_G);
JMenuItem newGameItem = new JMenuItem("New game");
newGameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
addMenuItem(newGameItem, gameMenu, KeyEvent.VK_N, "new", listener);
gameMenu.addSeparator();
addMenuItem(beginnerItem, gameMenu, KeyEvent.VK_B, "beginner", listener);
addMenuItem(intermediateItem, gameMenu, KeyEvent.VK_I, "intermediate", listener);
addMenuItem(expertItem, gameMenu, KeyEvent.VK_E, "expert", listener);
addMenuItem(customItem, gameMenu, KeyEvent.VK_C, "custom", listener);
gameMenu.addSeparator();
2023-05-24 17:34:20 -07:00
JCheckBoxMenuItem protectedStartItem = new JCheckBoxMenuItem("Protected Start",
Options.isProtectedStart());
2023-05-21 15:13:45 -07:00
protectedStartItem.setToolTipText("Guarantees the starting tile has no mines next to it");
addMenuItem(protectedStartItem, gameMenu, KeyEvent.VK_P, "protectedstart", listener);
2023-05-24 17:34:20 -07:00
JCheckBoxMenuItem soundItem = new JCheckBoxMenuItem("Sound", Options.hasSound());
addMenuItem(soundItem, gameMenu, KeyEvent.VK_U, "sound", listener);
2023-05-21 15:13:45 -07:00
gameMenu.addSeparator();
addMenuItem("Exit", gameMenu, KeyEvent.VK_X, "exit", listener);
menuBar.add(gameMenu);
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic(KeyEvent.VK_H);
JMenuItem helpItem = new JMenuItem("Help");
helpItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
addMenuItem(helpItem, helpMenu, KeyEvent.VK_H, "help", listener);
helpMenu.addSeparator();
addMenuItem("About", helpMenu, KeyEvent.VK_A, "about", listener);
menuBar.add(helpMenu);
JMenu skinsMenu = new JMenu("Skins");
skinsMenu.setMnemonic(KeyEvent.VK_S);
// The Skins menu should dynamically generate a menu of all image files
// in the skins directory when clicked in order to select one
skinsMenu.addMenuListener(new MenuListener() {
private static ActionListener skinListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Set the skin to the new one if it isn't already that
String newSkin = e.getActionCommand();
if (newSkin.equals(skin))
return;
skin = newSkin;
replaceCanvas();
}
};
@Override
public void menuSelected(MenuEvent e) {
// Get a stream of all files in the skins directory
try (Stream<Path> dirStream = Files.list(Paths.get(SKINS_DIR))) {
dirStream
2023-05-24 17:34:20 -07:00
// Filter for only regular files
.filter(Files::isRegularFile)
// Cut off the directory name from the resulting string
.map(Path::getFileName)
.map(Path::toString)
// Only allow a filename if it ends with one of the
// valid extensions
.filter(name -> Arrays.stream(VALID_EXTENSIONS)
// Use regionMatches to effectively
// case-insensitively endsWith()
.anyMatch(ext -> name.regionMatches(true,
name.length() - ext.length(), ext, 0, ext.length())))
// Because Files.list does not guarantee an order, and
// alphabetical files look objectively nicer in lists
.sorted()
// Create a radio button menu item for each one,
// remembering to have it pre-selected if it's already
// the current skin
.forEach(name -> addMenuItem(new JRadioButtonMenuItem(name, name.equals(skin)),
skinsMenu, name, skinListener));
2023-05-21 15:13:45 -07:00
} catch (IOException ignore) {
// It's fine to leave it blank if we can't get results
}
}
@Override
public void menuDeselected(MenuEvent e) {
// Remove skins when we're done so they don't duplicate every
// time we open the menu
skinsMenu.removeAll();
}
@Override
public void menuCanceled(MenuEvent e) {
}
});
menuBar.add(skinsMenu);
return menuBar;
}
private static void messageHtmlFile(String file, String failText, String title, int messageType) {
String text;
try {
// For some reason, JLabels just stop parsing HTML after they hit a
// newline, so swap the newlines out with spaces
text = Files.readString(Paths.get(file)).replace('\n', ' ');
} catch (IOException e) {
text = failText;
}
JOptionPane.showMessageDialog(FRAME, text, title, messageType);
}
private static void setDifficulty(Difficulty newDifficulty) {
2023-05-24 17:34:20 -07:00
// Reject switching difficulty to the already-existing one unless Custom
if (Options.getDifficulty() == newDifficulty && newDifficulty != Difficulty.CUSTOM)
2023-05-21 15:13:45 -07:00
return;
2023-05-24 17:34:20 -07:00
Options.setDifficulty(newDifficulty);
2023-05-21 15:13:45 -07:00
replaceCanvas();
}
private static void addMenuItem(String menuTitle, JMenu menu, int mnemonic, String actionCommand,
ActionListener listener) {
addMenuItem(new JMenuItem(menuTitle), menu, mnemonic, actionCommand, listener);
}
private static void addMenuItem(JMenuItem menuItem, JMenu menu, int mnemonic, String actionCommand,
ActionListener listener) {
menuItem.setMnemonic(mnemonic);
addMenuItem(menuItem, menu, actionCommand, listener);
}
private static void addMenuItem(JMenuItem menuItem, JMenu menu, String actionCommand,
ActionListener listener) {
menuItem.setActionCommand(actionCommand);
menuItem.addActionListener(listener);
menu.add(menuItem);
}
private static void replaceCanvas() {
canvas.stop();
canvas.removeAll();
FRAME.remove(canvas);
2023-05-24 17:34:20 -07:00
2023-05-21 15:13:45 -07:00
setCanvas();
2023-05-24 17:34:20 -07:00
canvas.requestFocusInWindow();
}
2023-05-21 15:13:45 -07:00
private static void setCanvas() {
2023-05-24 17:34:20 -07:00
canvas = new Canvas(new File(SKINS_DIR, skin));
2023-05-21 15:13:45 -07:00
FRAME.add(canvas);
FRAME.pack();
}
// No construction >:(
private Main() {
}
}