Compare commits
No commits in common. "v1.0" and "develop" have entirely different histories.
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="res"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="module" value="true"/>
|
<attribute name="module" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="lib" path="res"/>
|
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
@ -1,22 +1,12 @@
|
|||||||
package dev.kske.minesweeper;
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.*;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.FontMetrics;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Image;
|
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
@ -38,6 +28,7 @@ public class Board extends JPanel {
|
|||||||
private int mines, activeTiles, flaggedTiles;
|
private int mines, activeTiles, flaggedTiles;
|
||||||
private Tile[][] board;
|
private Tile[][] board;
|
||||||
private BoardConfig boardConfig;
|
private BoardConfig boardConfig;
|
||||||
|
private boolean minesPlaced;
|
||||||
|
|
||||||
private Instant start, finish;
|
private Instant start, finish;
|
||||||
|
|
||||||
@ -45,12 +36,16 @@ public class Board extends JPanel {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
icons = new HashMap<>();
|
icons = new HashMap<>();
|
||||||
final String[] names = { "mine2", "mine4", "tile", "tile3" };
|
for (String name : new String[] {
|
||||||
for (String name : names) {
|
"mine2", "mine4", "tile", "tile3"
|
||||||
|
}) {
|
||||||
icons.put(name, TextureLoader.loadScaledImage(name, tileSize));
|
icons.put(name, TextureLoader.loadScaledImage(name, tileSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link Board}.
|
||||||
|
*/
|
||||||
public Board() {
|
public Board() {
|
||||||
// Not using a layout manager
|
// Not using a layout manager
|
||||||
super(null);
|
super(null);
|
||||||
@ -62,7 +57,8 @@ public class Board extends JPanel {
|
|||||||
int n = evt.getX() / tileSize, m = evt.getY() / tileSize;
|
int n = evt.getX() / tileSize, m = evt.getY() / tileSize;
|
||||||
Tile tile = board[n][m];
|
Tile tile = board[n][m];
|
||||||
|
|
||||||
if (tile.isTouched() || gameState != GameState.ACTIVE) return;
|
if (tile.isTouched() || gameState != GameState.ACTIVE)
|
||||||
|
return;
|
||||||
switch (evt.getButton()) {
|
switch (evt.getButton()) {
|
||||||
case MouseEvent.BUTTON1:
|
case MouseEvent.BUTTON1:
|
||||||
touchTile(n, m);
|
touchTile(n, m);
|
||||||
@ -74,6 +70,11 @@ public class Board extends JPanel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the board with a given configuration. This does not include mine placement.
|
||||||
|
*
|
||||||
|
* @param config the configuration used
|
||||||
|
*/
|
||||||
public void init(BoardConfig config) {
|
public void init(BoardConfig config) {
|
||||||
boardConfig = config;
|
boardConfig = config;
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ public class Board extends JPanel {
|
|||||||
mines = config.mines;
|
mines = config.mines;
|
||||||
activeTiles = boardWidth * boardHeight;
|
activeTiles = boardWidth * boardHeight;
|
||||||
flaggedTiles = 0;
|
flaggedTiles = 0;
|
||||||
|
minesPlaced = false;
|
||||||
|
|
||||||
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
|
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
|
||||||
|
|
||||||
@ -94,13 +96,15 @@ public class Board extends JPanel {
|
|||||||
for (int i = 0; i < boardWidth; i++)
|
for (int i = 0; i < boardWidth; i++)
|
||||||
for (int j = 0; j < boardHeight; j++)
|
for (int j = 0; j < boardHeight; j++)
|
||||||
board[i][j] = new Tile();
|
board[i][j] = new Tile();
|
||||||
initMines();
|
|
||||||
repaint();
|
repaint();
|
||||||
revalidate();
|
revalidate();
|
||||||
|
|
||||||
start = Instant.now();
|
start = Instant.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-initializes the board with the cached configuration, thereby resetting it.
|
||||||
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
init(boardConfig);
|
init(boardConfig);
|
||||||
}
|
}
|
||||||
@ -118,31 +122,46 @@ public class Board extends JPanel {
|
|||||||
g.fillRect(x, y, x + tileSize, y + tileSize);
|
g.fillRect(x, y, x + tileSize, y + tileSize);
|
||||||
|
|
||||||
// Draw tile with normal mine
|
// Draw tile with normal mine
|
||||||
if (gameState == GameState.LOST && tile.isMine()) g.drawImage(icons.get("mine2"), x, y, this);
|
if (gameState == GameState.LOST && tile.isMine())
|
||||||
|
g.drawImage(icons.get("mine2"), x, y, this);
|
||||||
// Draw tile with diffused mine
|
// Draw tile with diffused mine
|
||||||
else if (gameState == GameState.WON && tile.isMine()) g.drawImage(icons.get("mine4"), x, y, this);
|
else
|
||||||
else if (tile.isTouched()) {
|
if (gameState == GameState.WON && tile.isMine())
|
||||||
|
g.drawImage(icons.get("mine4"), x, y, this);
|
||||||
|
else
|
||||||
|
if (tile.isTouched()) {
|
||||||
|
|
||||||
// Draw tile with mine
|
// Draw tile with mine
|
||||||
if (tile.isMine()) g.drawImage(icons.get("mine2"), x, y, this);
|
if (tile.isMine())
|
||||||
|
g.drawImage(icons.get("mine2"), x, y, this);
|
||||||
|
|
||||||
// Draw flagged tile
|
// Draw flagged tile
|
||||||
else if (tile.isDrawSurroundingMines() && tile.getSurroundingMines() > 0) {
|
else
|
||||||
|
if (
|
||||||
|
tile.isDrawSurroundingMines() && tile.getSurroundingMines() > 0
|
||||||
|
) {
|
||||||
// Draw number of surrounding mines
|
// Draw number of surrounding mines
|
||||||
String numStr = String.valueOf(tile.getSurroundingMines());
|
String numStr = String.valueOf(tile.getSurroundingMines());
|
||||||
g.setFont(new Font("Arial", Font.BOLD, 18));
|
g.setFont(new Font("Arial", Font.BOLD, 18));
|
||||||
g.setColor(Color.red);
|
g.setColor(Color.red);
|
||||||
FontMetrics fm = g.getFontMetrics();
|
FontMetrics fm = g.getFontMetrics();
|
||||||
int w = fm.stringWidth(numStr), h = fm.getHeight();
|
int w = fm.stringWidth(numStr), h = fm.getHeight();
|
||||||
g.drawString(numStr, x + (tileSize - w) / 2, y + (tileSize - h) / 2 + fm.getAscent());
|
g.drawString(
|
||||||
|
numStr,
|
||||||
|
x + (tileSize - w) / 2,
|
||||||
|
y + (tileSize - h) / 2 + fm.getAscent()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw flagged tile
|
// Draw flagged tile
|
||||||
else if (tile.isFlagged()) g.drawImage(icons.get("tile3"), x, y, this);
|
else
|
||||||
|
if (tile.isFlagged())
|
||||||
|
g.drawImage(icons.get("tile3"), x, y, this);
|
||||||
|
|
||||||
// Draw normal tile
|
// Draw normal tile
|
||||||
else g.drawImage(icons.get("tile"), x, y, this);
|
else
|
||||||
|
g.drawImage(icons.get("tile"), x, y, this);
|
||||||
|
|
||||||
// Draw grid
|
// Draw grid
|
||||||
((Graphics2D) g).setStroke(new BasicStroke(2.0f));
|
((Graphics2D) g).setStroke(new BasicStroke(2.0f));
|
||||||
@ -151,6 +170,11 @@ public class Board extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a game listener that is notified when game events occur.
|
||||||
|
*
|
||||||
|
* @param listener the game listener to register
|
||||||
|
*/
|
||||||
public void registerGameListener(GameListener listener) {
|
public void registerGameListener(GameListener listener) {
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
}
|
}
|
||||||
@ -176,7 +200,7 @@ public class Board extends JPanel {
|
|||||||
int m = random.nextInt(boardHeight);
|
int m = random.nextInt(boardHeight);
|
||||||
|
|
||||||
// Check if the selected tile already is a mine and is not touched
|
// Check if the selected tile already is a mine and is not touched
|
||||||
if (!board[n][m].isMine()) {
|
if (!board[n][m].isTouched() && !board[n][m].isMine()) {
|
||||||
// Decrement the counter
|
// Decrement the counter
|
||||||
remaining--;
|
remaining--;
|
||||||
|
|
||||||
@ -189,6 +213,7 @@ public class Board extends JPanel {
|
|||||||
board[i][j].setSurroundingMines(board[i][j].getSurroundingMines() + 1);
|
board[i][j].setSurroundingMines(board[i][j].getSurroundingMines() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
minesPlaced = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void touchTile(int n, int m) {
|
private void touchTile(int n, int m) {
|
||||||
@ -204,21 +229,25 @@ public class Board extends JPanel {
|
|||||||
flaggedTiles--;
|
flaggedTiles--;
|
||||||
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
|
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the game is won or lost
|
// Test if the game is won or lost
|
||||||
if (tile.isMine()) {
|
if (tile.isMine()) {
|
||||||
gameState = GameState.LOST;
|
gameState = GameState.LOST;
|
||||||
onGameOver();
|
onGameOver();
|
||||||
} else if (mines == activeTiles) {
|
} else
|
||||||
|
if (mines == activeTiles) {
|
||||||
gameState = GameState.WON;
|
gameState = GameState.WON;
|
||||||
onGameOver();
|
onGameOver();
|
||||||
}
|
}
|
||||||
|
// Place the mines if this was the first touch
|
||||||
|
if (!minesPlaced)
|
||||||
|
initMines();
|
||||||
|
|
||||||
// Touch surrounding tiles when there are zero surrounding mines
|
// Touch surrounding tiles when there are zero surrounding mines
|
||||||
else if (tile.getSurroundingMines() == 0)
|
if (tile.getSurroundingMines() == 0)
|
||||||
for (int i = Math.max(0, n - 1); i < Math.min(n + 2, board.length); i++)
|
for (int i = Math.max(0, n - 1); i < Math.min(n + 2, board.length); i++)
|
||||||
for (int j = Math.max(0, m - 1); j < Math.min(m + 2, board[i].length); j++)
|
for (int j = Math.max(0, m - 1); j < Math.min(m + 2, board[i].length); j++)
|
||||||
if (i != n || j != m) touchTile(i, j);
|
if (i != n || j != m)
|
||||||
|
touchTile(i, j);
|
||||||
|
|
||||||
repaintTile(n, m);
|
repaintTile(n, m);
|
||||||
}
|
}
|
||||||
@ -248,11 +277,23 @@ public class Board extends JPanel {
|
|||||||
notifyGameStateEvent(evt);
|
notifyGameStateEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the total number of mines
|
||||||
|
*/
|
||||||
public int getMines() { return mines; }
|
public int getMines() { return mines; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of active tiles
|
||||||
|
*/
|
||||||
public int getActiveTiles() { return activeTiles; }
|
public int getActiveTiles() { return activeTiles; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of flagged files
|
||||||
|
*/
|
||||||
public int getFlaggedTiles() { return flaggedTiles; }
|
public int getFlaggedTiles() { return flaggedTiles; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current configuration
|
||||||
|
*/
|
||||||
public BoardConfig getBoardConfig() { return boardConfig; }
|
public BoardConfig getBoardConfig() { return boardConfig; }
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package dev.kske.minesweeper;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Defines board configuration consisting of board with and height as well as mine count.
|
||||||
|
* <p>
|
||||||
* Project: <strong>Minesweeper</strong><br>
|
* Project: <strong>Minesweeper</strong><br>
|
||||||
* File: <strong>BoardConfig.java</strong><br>
|
* File: <strong>BoardConfig.java</strong><br>
|
||||||
* Created: <strong>01.04.2019</strong><br>
|
* Created: <strong>01.04.2019</strong><br>
|
||||||
@ -12,7 +14,8 @@ 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),
|
public static final BoardConfig EASY = new BoardConfig(8, 8, 10), MEDIUM
|
||||||
|
= new BoardConfig(16, 16, 40),
|
||||||
HARD = new BoardConfig(30, 16, 99);
|
HARD = new BoardConfig(30, 16, 99);
|
||||||
|
|
||||||
public final int width, height, mines;
|
public final int width, height, mines;
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
package dev.kske.minesweeper;
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.*;
|
||||||
import java.awt.FlowLayout;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Frame;
|
|
||||||
import java.awt.GridLayout;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.*;
|
||||||
import javax.swing.JDialog;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,6 +20,8 @@ public class CustomDialog extends JDialog {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the dialog.
|
* Create the dialog.
|
||||||
|
*
|
||||||
|
* @param owner the frame on top of which the dialog will be displayed
|
||||||
*/
|
*/
|
||||||
public CustomDialog(Frame owner) {
|
public CustomDialog(Frame owner) {
|
||||||
super(owner, ModalityType.APPLICATION_MODAL);
|
super(owner, ModalityType.APPLICATION_MODAL);
|
||||||
@ -47,7 +41,9 @@ public class CustomDialog extends JDialog {
|
|||||||
lblBoardWidth.setFont(new Font("Tahoma", Font.PLAIN, 14));
|
lblBoardWidth.setFont(new Font("Tahoma", Font.PLAIN, 14));
|
||||||
mcontentPanel.add(lblBoardWidth);
|
mcontentPanel.add(lblBoardWidth);
|
||||||
JSlider sliderBoardWidth = new JSlider();
|
JSlider sliderBoardWidth = new JSlider();
|
||||||
sliderBoardWidth.addChangeListener((evt) -> lblBoardWidth.setText(String.valueOf(sliderBoardWidth.getValue())));
|
sliderBoardWidth.addChangeListener(
|
||||||
|
(evt) -> lblBoardWidth.setText(String.valueOf(sliderBoardWidth.getValue()))
|
||||||
|
);
|
||||||
sliderBoardWidth.setValue(16);
|
sliderBoardWidth.setValue(16);
|
||||||
sliderBoardWidth.setMinimum(2);
|
sliderBoardWidth.setMinimum(2);
|
||||||
sliderBoardWidth.setMaximum(30);
|
sliderBoardWidth.setMaximum(30);
|
||||||
@ -76,7 +72,9 @@ public class CustomDialog extends JDialog {
|
|||||||
lblNumMines.setFont(new Font("Tahoma", Font.PLAIN, 14));
|
lblNumMines.setFont(new Font("Tahoma", Font.PLAIN, 14));
|
||||||
mcontentPanel.add(lblNumMines);
|
mcontentPanel.add(lblNumMines);
|
||||||
JSlider sliderNumMines = new JSlider();
|
JSlider sliderNumMines = new JSlider();
|
||||||
sliderNumMines.addChangeListener((evt) -> lblNumMines.setText(String.valueOf(sliderNumMines.getValue())));
|
sliderNumMines.addChangeListener(
|
||||||
|
(evt) -> lblNumMines.setText(String.valueOf(sliderNumMines.getValue()))
|
||||||
|
);
|
||||||
sliderNumMines.setValue(16);
|
sliderNumMines.setValue(16);
|
||||||
sliderNumMines.setMinimum(2);
|
sliderNumMines.setMinimum(2);
|
||||||
sliderNumMines.setMaximum(200);
|
sliderNumMines.setMaximum(200);
|
||||||
@ -89,8 +87,11 @@ public class CustomDialog extends JDialog {
|
|||||||
JButton okButton = new JButton("Start Game");
|
JButton okButton = new JButton("Start Game");
|
||||||
okButton.setActionCommand("OK");
|
okButton.setActionCommand("OK");
|
||||||
okButton.addActionListener((evt) -> {
|
okButton.addActionListener((evt) -> {
|
||||||
result = new BoardConfig(sliderBoardWidth.getValue(), sliderBoardHeight.getValue(),
|
result = new BoardConfig(
|
||||||
sliderNumMines.getValue());
|
sliderBoardWidth.getValue(),
|
||||||
|
sliderBoardHeight.getValue(),
|
||||||
|
sliderNumMines.getValue()
|
||||||
|
);
|
||||||
dispose();
|
dispose();
|
||||||
});
|
});
|
||||||
buttonPane.add(okButton);
|
buttonPane.add(okButton);
|
||||||
@ -105,6 +106,11 @@ public class CustomDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the dialog.
|
||||||
|
*
|
||||||
|
* @return the board configuration defined by the user
|
||||||
|
*/
|
||||||
public BoardConfig showDialog() {
|
public BoardConfig showDialog() {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
return result;
|
return result;
|
||||||
|
@ -17,7 +17,9 @@ public class GameOverEvent extends EventObject {
|
|||||||
private final BoardConfig boardConfig;
|
private final BoardConfig boardConfig;
|
||||||
private final int duration;
|
private final int duration;
|
||||||
|
|
||||||
public GameOverEvent(Object source, GameState gameState, BoardConfig boardConfig, int duration) {
|
public GameOverEvent(
|
||||||
|
Object source, GameState gameState, BoardConfig boardConfig, int duration
|
||||||
|
) {
|
||||||
super(source);
|
super(source);
|
||||||
board = (Board) source;
|
board = (Board) source;
|
||||||
this.gameState = gameState;
|
this.gameState = gameState;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package dev.kske.minesweeper;
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
import static dev.kske.minesweeper.BoardConfig.EASY;
|
import static dev.kske.minesweeper.BoardConfig.*;
|
||||||
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;
|
||||||
@ -10,17 +8,7 @@ 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 javax.swing.JButton;
|
import javax.swing.*;
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuBar;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.SwingConstants;
|
|
||||||
import javax.swing.Timer;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Minesweeper</strong><br>
|
* Project: <strong>Minesweeper</strong><br>
|
||||||
@ -30,7 +18,7 @@ import javax.swing.UIManager;
|
|||||||
*/
|
*/
|
||||||
public class Minesweeper {
|
public class Minesweeper {
|
||||||
|
|
||||||
private static final String VERSION = "1.0";
|
private static final String VERSION = "1.1";
|
||||||
|
|
||||||
private JFrame mframe;
|
private JFrame mframe;
|
||||||
|
|
||||||
@ -41,6 +29,8 @@ public class Minesweeper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
|
*
|
||||||
|
* @param args command line arguments are ignored
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
EventQueue.invokeLater(() -> {
|
EventQueue.invokeLater(() -> {
|
||||||
@ -71,7 +61,6 @@ public class Minesweeper {
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
mframe = new JFrame();
|
mframe = new JFrame();
|
||||||
mframe.addWindowListener(new WindowAdapter() {
|
mframe.addWindowListener(new WindowAdapter() {
|
||||||
|
|
||||||
@ -115,11 +104,16 @@ public class Minesweeper {
|
|||||||
JLabel lblRemainingMines = new JLabel("Remaining Mines: " + EASY.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) -> { board.reset(); gameTime = 0; timer.restart(); });
|
btnRestart.addActionListener((evt) -> {
|
||||||
|
board.reset();
|
||||||
|
gameTime = 0;
|
||||||
|
timer.restart();
|
||||||
|
});
|
||||||
mframe.pack();
|
mframe.pack();
|
||||||
|
|
||||||
board.registerGameListener(new GameListener() {
|
board.registerGameListener(new GameListener() {
|
||||||
|
|
||||||
|
@SuppressWarnings("incomplete-switch")
|
||||||
@Override
|
@Override
|
||||||
public void onGameOverEvent(GameOverEvent evt) {
|
public void onGameOverEvent(GameOverEvent evt) {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
@ -135,7 +129,8 @@ public class Minesweeper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFlaggedTilesEvent(FlaggedTilesEvent evt) {
|
public void onFlaggedTilesEvent(FlaggedTilesEvent evt) {
|
||||||
lblRemainingMines.setText("Remaining Mines: " + (evt.getBoard().getMines() - evt.getFlagged()));
|
lblRemainingMines
|
||||||
|
.setText("Remaining Mines: " + (evt.getBoard().getMines() - evt.getFlagged()));
|
||||||
mframe.pack();
|
mframe.pack();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -167,7 +162,8 @@ public class Minesweeper {
|
|||||||
hardMenuItem.addActionListener((evt) -> initGame(HARD));
|
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(easyMenuItem);
|
||||||
@ -177,7 +173,6 @@ public class Minesweeper {
|
|||||||
gameMenu.add(customMenuItem);
|
gameMenu.add(customMenuItem);
|
||||||
menubar.add(gameMenu);
|
menubar.add(gameMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var highscoreMenu = new JMenu("Highscores");
|
var highscoreMenu = new JMenu("Highscores");
|
||||||
|
|
||||||
@ -199,16 +194,17 @@ public class Minesweeper {
|
|||||||
highscoreMenu.add(hardMenuItem);
|
highscoreMenu.add(hardMenuItem);
|
||||||
menubar.add(highscoreMenu);
|
menubar.add(highscoreMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var aboutMenuItem = new JMenuItem("About");
|
var aboutMenuItem = new JMenuItem("About");
|
||||||
|
|
||||||
aboutMenuItem.addActionListener((evt) -> JOptionPane.showMessageDialog(board,
|
aboutMenuItem.addActionListener(
|
||||||
"Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"));
|
(evt) -> JOptionPane.showMessageDialog(board,
|
||||||
|
"Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
menubar.add(aboutMenuItem);
|
menubar.add(aboutMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
mframe.setJMenuBar(menubar);
|
mframe.setJMenuBar(menubar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,7 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JDialog;
|
import javax.swing.*;
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.SwingConstants;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Minesweeper</strong><br>
|
* Project: <strong>Minesweeper</strong><br>
|
||||||
@ -25,6 +21,10 @@ public class ScoreDialog extends JDialog {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the dialog.
|
* Create the dialog.
|
||||||
|
*
|
||||||
|
* @param scores the scores to display
|
||||||
|
* @param boardConfigName the name of the board configuration with which the scores are
|
||||||
|
* associated
|
||||||
*/
|
*/
|
||||||
public ScoreDialog(List<Score> scores, String boardConfigName) {
|
public ScoreDialog(List<Score> scores, String boardConfigName) {
|
||||||
setModal(true);
|
setModal(true);
|
||||||
@ -32,7 +32,9 @@ public class ScoreDialog extends JDialog {
|
|||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
getContentPane().setLayout(new BorderLayout(0, 0));
|
getContentPane().setLayout(new BorderLayout(0, 0));
|
||||||
|
|
||||||
String[] columnNames = { "Place", "Name", "Duration", "Date" };
|
String[] columnNames = {
|
||||||
|
"Place", "Name", "Duration", "Date"
|
||||||
|
};
|
||||||
String[][] data = new String[scores.size()][4];
|
String[][] data = new String[scores.size()][4];
|
||||||
Iterator<Score> iter = scores.iterator();
|
Iterator<Score> iter = scores.iterator();
|
||||||
for (int i = 0; i < data.length; i++) {
|
for (int i = 0; i < data.length; i++) {
|
||||||
@ -42,7 +44,6 @@ public class ScoreDialog extends JDialog {
|
|||||||
data[i][2] = String.valueOf(s.getDuration());
|
data[i][2] = String.valueOf(s.getDuration());
|
||||||
data[i][3] = new SimpleDateFormat().format(s.getDate());
|
data[i][3] = new SimpleDateFormat().format(s.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
mtable = new JTable(data, columnNames);
|
mtable = new JTable(data, columnNames);
|
||||||
getContentPane().add(mtable);
|
getContentPane().add(mtable);
|
||||||
|
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
package dev.kske.minesweeper;
|
package dev.kske.minesweeper;
|
||||||
|
|
||||||
import static dev.kske.minesweeper.BoardConfig.EASY;
|
import static dev.kske.minesweeper.BoardConfig.*;
|
||||||
import static dev.kske.minesweeper.BoardConfig.HARD;
|
|
||||||
import static dev.kske.minesweeper.BoardConfig.MEDIUM;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.*;
|
||||||
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.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -40,11 +33,19 @@ public class ScoreManager {
|
|||||||
String name = JOptionPane.showInputDialog("Please enter your name");
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
Score score = new Score(name, evt.getDuration(), new Date());
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
sortInsert(score, easy);
|
sortInsert(score, easy);
|
||||||
} else if (config == MEDIUM && (medium.size() < 10 || medium.get(9).getDuration() > evt.getDuration())) {
|
} else
|
||||||
|
if (
|
||||||
|
config == MEDIUM
|
||||||
|
&& (medium.size() < 10 || medium.get(9).getDuration() > evt.getDuration())
|
||||||
|
) {
|
||||||
String name = JOptionPane.showInputDialog("Please enter your name");
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
Score score = new Score(name, evt.getDuration(), new Date());
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
sortInsert(score, medium);
|
sortInsert(score, medium);
|
||||||
} else if (config == HARD && (hard.size() < 10 || hard.get(9).getDuration() > evt.getDuration())) {
|
} else
|
||||||
|
if (
|
||||||
|
config == HARD
|
||||||
|
&& (hard.size() < 10 || hard.get(9).getDuration() > evt.getDuration())
|
||||||
|
) {
|
||||||
String name = JOptionPane.showInputDialog("Please enter your name");
|
String name = JOptionPane.showInputDialog("Please enter your name");
|
||||||
Score score = new Score(name, evt.getDuration(), new Date());
|
Score score = new Score(name, evt.getDuration(), new Date());
|
||||||
sortInsert(score, hard);
|
sortInsert(score, hard);
|
||||||
@ -76,16 +77,23 @@ public class ScoreManager {
|
|||||||
public void loadScores() {
|
public void loadScores() {
|
||||||
try (var in = new ObjectInputStream(new FileInputStream(scoresFile))) {
|
try (var in = new ObjectInputStream(new FileInputStream(scoresFile))) {
|
||||||
Object obj = in.readObject();
|
Object obj = in.readObject();
|
||||||
if (obj instanceof ArrayList<?>) easy = (ArrayList<Score>) obj;
|
if (obj instanceof ArrayList<?>)
|
||||||
|
easy = (ArrayList<Score>) obj;
|
||||||
obj = in.readObject();
|
obj = in.readObject();
|
||||||
if (obj instanceof ArrayList<?>) medium = (ArrayList<Score>) obj;
|
if (obj instanceof ArrayList<?>)
|
||||||
|
medium = (ArrayList<Score>) obj;
|
||||||
obj = in.readObject();
|
obj = in.readObject();
|
||||||
if (obj instanceof ArrayList<?>) hard = (ArrayList<Score>) obj;
|
if (obj instanceof ArrayList<?>)
|
||||||
else throw new IOException("Serialized object has the wrong class.");
|
hard = (ArrayList<Score>) obj;
|
||||||
|
else
|
||||||
|
throw new IOException("Serialized object has the wrong class.");
|
||||||
} catch (FileNotFoundException ex) {} catch (IOException | ClassNotFoundException ex) {
|
} catch (FileNotFoundException ex) {} catch (IOException | ClassNotFoundException ex) {
|
||||||
JOptionPane.showMessageDialog(null,
|
JOptionPane.showMessageDialog(
|
||||||
"The score file seems to be corrupted. It will be replaced when closing the game.", "File error",
|
null,
|
||||||
JOptionPane.ERROR_MESSAGE);
|
"The score file seems to be corrupted. It will be replaced when closing the game.",
|
||||||
|
"File error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package dev.kske.minesweeper;
|
|||||||
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -28,7 +27,7 @@ public class TextureLoader {
|
|||||||
public static Image loadScaledImage(String name, int scale) {
|
public static Image loadScaledImage(String name, int scale) {
|
||||||
BufferedImage in = null;
|
BufferedImage in = null;
|
||||||
try {
|
try {
|
||||||
in = ImageIO.read(new File("res" + File.separator + name + ".png"));
|
in = ImageIO.read(TextureLoader.class.getResourceAsStream("/" + name + ".png"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -39,5 +39,7 @@ public class Tile {
|
|||||||
|
|
||||||
public int getSurroundingMines() { return surroundingMines; }
|
public int getSurroundingMines() { return surroundingMines; }
|
||||||
|
|
||||||
public void setSurroundingMines(int surroundingMines) { this.surroundingMines = surroundingMines; }
|
public void setSurroundingMines(int surroundingMines) {
|
||||||
|
this.surroundingMines = surroundingMines;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Contains all classes related to the game.
|
||||||
|
*/
|
||||||
module Minesweeper {
|
module Minesweeper {
|
||||||
requires java.desktop;
|
requires java.desktop;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user