Added proper score management
- Added ScoreManager - Altered ScoreDialog to show only scores of a specific BoardConfig - Removed BoardConfig dependency from Score - Added the constants EASY, MEDIUM and HARD to BoardConfig - Removed score backend handling from Minesweeper, added a highscore menu
This commit is contained in:
parent
5f408ff383
commit
7400795737
@ -12,6 +12,9 @@ public class BoardConfig implements Serializable {
|
|||||||
|
|
||||||
private static final long serialVersionUID = -6083006887427383946L;
|
private static final long serialVersionUID = -6083006887427383946L;
|
||||||
|
|
||||||
|
public static final BoardConfig EASY = new BoardConfig(8, 8, 10), MEDIUM = new BoardConfig(16, 16, 40),
|
||||||
|
HARD = new BoardConfig(30, 16, 99);
|
||||||
|
|
||||||
public final int width, height, mines;
|
public final int width, height, mines;
|
||||||
|
|
||||||
public BoardConfig(int width, int height, int mines) {
|
public BoardConfig(int width, int height, int mines) {
|
||||||
@ -19,9 +22,4 @@ public class BoardConfig implements Serializable {
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
this.mines = mines;
|
this.mines = mines;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("%d %d %d", width, height, mines);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
package dev.kske.minesweeper;
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.EASY;
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.HARD;
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.MEDIUM;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
@ -34,17 +30,14 @@ import javax.swing.UIManager;
|
|||||||
*/
|
*/
|
||||||
public class Minesweeper {
|
public class Minesweeper {
|
||||||
|
|
||||||
private static final String VERSION = "1.1 JE";
|
private static final String VERSION = "1.2 JE";
|
||||||
|
|
||||||
private JFrame mframe;
|
private JFrame mframe;
|
||||||
|
|
||||||
private Board board;
|
private Board board;
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private int gameTime;
|
private int gameTime;
|
||||||
private TreeSet<Score> scores;
|
private ScoreManager scoreManager;
|
||||||
private final String scoresFile = "scores.ser";
|
|
||||||
private final BoardConfig easyConfig = new BoardConfig(8, 8, 10), mediumConfig = new BoardConfig(16, 16, 40),
|
|
||||||
hardConfig = new BoardConfig(30, 16, 99);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
@ -84,7 +77,7 @@ public class Minesweeper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
saveScores();
|
scoreManager.saveScores();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mframe.setResizable(false);
|
mframe.setResizable(false);
|
||||||
@ -95,7 +88,7 @@ public class Minesweeper {
|
|||||||
createMenuBar();
|
createMenuBar();
|
||||||
|
|
||||||
board = new Board();
|
board = new Board();
|
||||||
board.init(easyConfig);
|
board.init(EASY);
|
||||||
mframe.getContentPane().setLayout(new BorderLayout(0, 0));
|
mframe.getContentPane().setLayout(new BorderLayout(0, 0));
|
||||||
mframe.getContentPane().add(board, BorderLayout.CENTER);
|
mframe.getContentPane().add(board, BorderLayout.CENTER);
|
||||||
|
|
||||||
@ -119,7 +112,7 @@ public class Minesweeper {
|
|||||||
timer.setInitialDelay(0);
|
timer.setInitialDelay(0);
|
||||||
timer.setCoalesce(true);
|
timer.setCoalesce(true);
|
||||||
|
|
||||||
JLabel lblRemainingMines = new JLabel("Remaining Mines: " + easyConfig.mines);
|
JLabel lblRemainingMines = new JLabel("Remaining Mines: " + EASY.mines);
|
||||||
panel.add(lblRemainingMines, BorderLayout.SOUTH);
|
panel.add(lblRemainingMines, BorderLayout.SOUTH);
|
||||||
lblRemainingMines.setHorizontalAlignment(SwingConstants.LEFT);
|
lblRemainingMines.setHorizontalAlignment(SwingConstants.LEFT);
|
||||||
btnRestart.addActionListener((evt) -> {
|
btnRestart.addActionListener((evt) -> {
|
||||||
@ -140,11 +133,7 @@ public class Minesweeper {
|
|||||||
break;
|
break;
|
||||||
case WON:
|
case WON:
|
||||||
JOptionPane.showMessageDialog(mframe, "Game won!");
|
JOptionPane.showMessageDialog(mframe, "Game won!");
|
||||||
if (scores.size() < 10 || scores.last().getDuration() > evt.getDuration()) {
|
scoreManager.addScore(evt);
|
||||||
String name = JOptionPane.showInputDialog("Please enter your name");
|
|
||||||
Score score = new Score(name, evt.getDuration(), new Date(), evt.getBoardConfig());
|
|
||||||
scores.add(score);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,76 +144,76 @@ public class Minesweeper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loadScores();
|
scoreManager = new ScoreManager();
|
||||||
|
scoreManager.loadScores();
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createMenuBar() {
|
private void createMenuBar() {
|
||||||
var menubar = new JMenuBar();
|
var menubar = new JMenuBar();
|
||||||
|
|
||||||
var gameMenu = new JMenu("Game");
|
{
|
||||||
var highscoreMenuItem = new JMenuItem("Highscores");
|
var gameMenu = new JMenu("Game");
|
||||||
var aboutMenuItem = new JMenuItem("About");
|
|
||||||
|
|
||||||
var easyMenuItem = new JMenuItem("Easy");
|
var easyMenuItem = new JMenuItem("Easy");
|
||||||
var mediumMenuItem = new JMenuItem("Medium");
|
var mediumMenuItem = new JMenuItem("Medium");
|
||||||
var hardMenuItem = new JMenuItem("Hard");
|
var hardMenuItem = new JMenuItem("Hard");
|
||||||
var customMenuItem = new JMenuItem("Custom");
|
var customMenuItem = new JMenuItem("Custom");
|
||||||
|
|
||||||
gameMenu.setMnemonic(KeyEvent.VK_G);
|
gameMenu.setMnemonic(KeyEvent.VK_G);
|
||||||
easyMenuItem.setMnemonic(KeyEvent.VK_E);
|
easyMenuItem.setMnemonic(KeyEvent.VK_E);
|
||||||
mediumMenuItem.setMnemonic(KeyEvent.VK_M);
|
mediumMenuItem.setMnemonic(KeyEvent.VK_M);
|
||||||
hardMenuItem.setMnemonic(KeyEvent.VK_H);
|
hardMenuItem.setMnemonic(KeyEvent.VK_H);
|
||||||
customMenuItem.setMnemonic(KeyEvent.VK_C);
|
customMenuItem.setMnemonic(KeyEvent.VK_C);
|
||||||
|
|
||||||
easyMenuItem.addActionListener((evt) -> initGame(easyConfig));
|
easyMenuItem.addActionListener((evt) -> initGame(EASY));
|
||||||
mediumMenuItem.addActionListener((evt) -> initGame(mediumConfig));
|
mediumMenuItem.addActionListener((evt) -> initGame(MEDIUM));
|
||||||
hardMenuItem.addActionListener((evt) -> initGame(hardConfig));
|
hardMenuItem.addActionListener((evt) -> initGame(HARD));
|
||||||
customMenuItem.addActionListener((evt) -> {
|
customMenuItem.addActionListener((evt) -> {
|
||||||
BoardConfig cfg = new CustomDialog(mframe).showDialog();
|
BoardConfig cfg = new CustomDialog(mframe).showDialog();
|
||||||
if (cfg != null) initGame(cfg);
|
if (cfg != null) initGame(cfg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gameMenu.add(easyMenuItem);
|
||||||
|
gameMenu.add(mediumMenuItem);
|
||||||
|
gameMenu.add(hardMenuItem);
|
||||||
|
gameMenu.addSeparator();
|
||||||
|
gameMenu.add(customMenuItem);
|
||||||
|
menubar.add(gameMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var highscoreMenu = new JMenu("Highscores");
|
||||||
|
|
||||||
|
var easyMenuItem = new JMenuItem("Easy");
|
||||||
|
var mediumMenuItem = new JMenuItem("Medium");
|
||||||
|
var hardMenuItem = new JMenuItem("Hard");
|
||||||
|
|
||||||
|
highscoreMenu.setMnemonic(KeyEvent.VK_H);
|
||||||
|
easyMenuItem.setMnemonic(KeyEvent.VK_E);
|
||||||
|
mediumMenuItem.setMnemonic(KeyEvent.VK_M);
|
||||||
|
hardMenuItem.setMnemonic(KeyEvent.VK_H);
|
||||||
|
|
||||||
|
easyMenuItem.addActionListener((evt) -> scoreManager.displayEasy());
|
||||||
|
mediumMenuItem.addActionListener((evt) -> scoreManager.displayMedium());
|
||||||
|
hardMenuItem.addActionListener((evt) -> scoreManager.displayHard());
|
||||||
|
|
||||||
|
highscoreMenu.add(easyMenuItem);
|
||||||
|
highscoreMenu.add(mediumMenuItem);
|
||||||
|
highscoreMenu.add(hardMenuItem);
|
||||||
|
menubar.add(highscoreMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
var aboutMenuItem = new JMenuItem("About");
|
||||||
|
|
||||||
highscoreMenuItem.addActionListener((evt) -> new ScoreDialog(scores).setVisible(true));
|
|
||||||
aboutMenuItem.addActionListener((evt) -> JOptionPane.showMessageDialog(board,
|
aboutMenuItem.addActionListener((evt) -> JOptionPane.showMessageDialog(board,
|
||||||
"Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"));
|
"Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"));
|
||||||
|
|
||||||
gameMenu.add(easyMenuItem);
|
|
||||||
gameMenu.add(mediumMenuItem);
|
|
||||||
gameMenu.add(hardMenuItem);
|
|
||||||
gameMenu.addSeparator();
|
|
||||||
gameMenu.add(customMenuItem);
|
|
||||||
menubar.add(gameMenu);
|
|
||||||
menubar.add(highscoreMenuItem);
|
|
||||||
menubar.add(aboutMenuItem);
|
menubar.add(aboutMenuItem);
|
||||||
|
|
||||||
mframe.setJMenuBar(menubar);
|
mframe.setJMenuBar(menubar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void loadScores() {
|
|
||||||
try (var in = new ObjectInputStream(new FileInputStream(scoresFile))) {
|
|
||||||
Object obj = in.readObject();
|
|
||||||
if (obj instanceof TreeSet<?>) scores = (TreeSet<Score>) obj;
|
|
||||||
else throw new IOException("Serialized object has the wrong class.");
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
scores = new TreeSet<>();
|
|
||||||
} catch (IOException | ClassNotFoundException ex) {
|
|
||||||
JOptionPane.showMessageDialog(mframe,
|
|
||||||
"The score file seems to be corrupted. It will be replaced when closing the game.", "File error",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
scores = new TreeSet<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveScores() {
|
|
||||||
try (var out = new ObjectOutputStream(new FileOutputStream(scoresFile))) {
|
|
||||||
out.writeObject(scores);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGame(BoardConfig config) {
|
private void initGame(BoardConfig config) {
|
||||||
board.init(config);
|
board.init(config);
|
||||||
gameTime = 0;
|
gameTime = 0;
|
||||||
|
@ -16,13 +16,11 @@ public class Score implements Comparable<Score>, Serializable {
|
|||||||
private final String name;
|
private final String name;
|
||||||
private final int duration;
|
private final int duration;
|
||||||
private final Date date;
|
private final Date date;
|
||||||
private final BoardConfig boardConfig;
|
|
||||||
|
|
||||||
public Score(String name, int duration, Date date, BoardConfig boardConfig) {
|
public Score(String name, int duration, Date date) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.boardConfig = boardConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
@ -31,8 +29,6 @@ public class Score implements Comparable<Score>, Serializable {
|
|||||||
|
|
||||||
public Date getDate() { return date; }
|
public Date getDate() { return date; }
|
||||||
|
|
||||||
public BoardConfig getBoardConfig() { return boardConfig; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Score other) {
|
public int compareTo(Score other) {
|
||||||
return Integer.compare(duration, other.duration);
|
return Integer.compare(duration, other.duration);
|
||||||
|
@ -4,7 +4,7 @@ import java.awt.BorderLayout;
|
|||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
@ -26,7 +26,7 @@ public class ScoreDialog extends JDialog {
|
|||||||
/**
|
/**
|
||||||
* Create the dialog.
|
* Create the dialog.
|
||||||
*/
|
*/
|
||||||
public ScoreDialog(Set<Score> scores) {
|
public ScoreDialog(List<Score> scores, String boardConfigName) {
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setBounds(100, 100, 450, 300);
|
setBounds(100, 100, 450, 300);
|
||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
@ -39,7 +39,7 @@ public class ScoreDialog extends JDialog {
|
|||||||
Score s = iter.next();
|
Score s = iter.next();
|
||||||
data[i][0] = s.getName();
|
data[i][0] = s.getName();
|
||||||
data[i][1] = String.valueOf(s.getDuration());
|
data[i][1] = String.valueOf(s.getDuration());
|
||||||
data[i][2] = s.getBoardConfig().toString();
|
data[i][2] = boardConfigName;
|
||||||
data[i][3] = new SimpleDateFormat().format(s.getDate());
|
data[i][3] = new SimpleDateFormat().format(s.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ public class ScoreDialog extends JDialog {
|
|||||||
|
|
||||||
panel.add(mtable.getTableHeader(), BorderLayout.CENTER);
|
panel.add(mtable.getTableHeader(), BorderLayout.CENTER);
|
||||||
|
|
||||||
JLabel lblHighscores = new JLabel("Highscores");
|
JLabel lblHighscores = new JLabel("Highscores: " + boardConfigName);
|
||||||
panel.add(lblHighscores, BorderLayout.NORTH);
|
panel.add(lblHighscores, BorderLayout.NORTH);
|
||||||
lblHighscores.setFont(new Font("Tahoma", Font.BOLD, 16));
|
lblHighscores.setFont(new Font("Tahoma", Font.BOLD, 16));
|
||||||
lblHighscores.setHorizontalAlignment(SwingConstants.CENTER);
|
lblHighscores.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
92
src/dev/kske/minesweeper/ScoreManager.java
Normal file
92
src/dev/kske/minesweeper/ScoreManager.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.EASY;
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.HARD;
|
||||||
|
import static dev.kske.minesweeper.BoardConfig.MEDIUM;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>Minesweeper</strong><br>
|
||||||
|
* File: <strong>ScoreManager.java</strong><br>
|
||||||
|
* Created: <strong>15.05.2019</strong><br>
|
||||||
|
* Author: <strong>Kai S. K. Engelbart</strong>
|
||||||
|
*/
|
||||||
|
public class ScoreManager {
|
||||||
|
|
||||||
|
private List<Score> easy, medium, hard;
|
||||||
|
private final String scoresFile = "scores.ser";
|
||||||
|
|
||||||
|
public ScoreManager() {
|
||||||
|
easy = new ArrayList<>();
|
||||||
|
medium = new ArrayList<>();
|
||||||
|
hard = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addScore(GameOverEvent evt) {
|
||||||
|
// Determine board config
|
||||||
|
BoardConfig config = evt.getBoardConfig();
|
||||||
|
if (config == EASY && (easy.size() < 10 || easy.get(9).getDuration() > evt.getDuration())) {
|
||||||
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
|
easy.add(score);
|
||||||
|
} else if (config == MEDIUM && (medium.size() < 10 || medium.get(9).getDuration() > evt.getDuration())) {
|
||||||
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
|
medium.add(score);
|
||||||
|
} else if (config == HARD && (hard.size() < 10 || hard.get(9).getDuration() > evt.getDuration())) {
|
||||||
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
|
hard.add(score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayEasy() {
|
||||||
|
new ScoreDialog(easy, "Easy").setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayMedium() {
|
||||||
|
new ScoreDialog(medium, "Medium").setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayHard() {
|
||||||
|
new ScoreDialog(hard, "Hard").setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void loadScores() {
|
||||||
|
try (var in = new ObjectInputStream(new FileInputStream(scoresFile))) {
|
||||||
|
Object obj = in.readObject();
|
||||||
|
if (obj instanceof ArrayList<?>) easy = (ArrayList<Score>) obj;
|
||||||
|
obj = in.readObject();
|
||||||
|
if (obj instanceof ArrayList<?>) medium = (ArrayList<Score>) obj;
|
||||||
|
obj = in.readObject();
|
||||||
|
if (obj instanceof ArrayList<?>) hard = (ArrayList<Score>) obj;
|
||||||
|
else throw new IOException("Serialized object has the wrong class.");
|
||||||
|
} catch (FileNotFoundException ex) {} catch (IOException | ClassNotFoundException ex) {
|
||||||
|
JOptionPane.showMessageDialog(null,
|
||||||
|
"The score file seems to be corrupted. It will be replaced when closing the game.", "File error",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveScores() {
|
||||||
|
try (var out = new ObjectOutputStream(new FileOutputStream(scoresFile))) {
|
||||||
|
out.writeObject(easy);
|
||||||
|
out.writeObject(medium);
|
||||||
|
out.writeObject(hard);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user