Added events for changes of the game state and flagged tiles

This commit is contained in:
Kai S. K. Engelbart 2019-04-03 08:50:23 +02:00
parent 0b927c5c9f
commit 5535a59a73
6 changed files with 196 additions and 4 deletions

View File

@ -8,7 +8,9 @@ import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
@ -31,8 +33,9 @@ public class Board extends JPanel {
private GameState gameState;
private int mines, activeTiles, flaggedTiles;
private Tile[][] board;
private BoardConfig initialConfig;
private BoardConfig initialConfig;
private List<GameListener> listeners;
static {
icons = new HashMap<>();
@ -45,6 +48,7 @@ public class Board extends JPanel {
public Board() {
// Not using a layout manager
super(null);
listeners = new ArrayList<>();
addMouseListener(new MouseAdapter() {
@Override
@ -84,6 +88,7 @@ public class Board extends JPanel {
for (int j = 0; j < boardHeight; j++)
board[i][j] = new Tile();
initMines();
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
repaint();
}
@ -91,6 +96,18 @@ public class Board extends JPanel {
init(initialConfig);
}
public void registerGameListener(GameListener listener) {
listeners.add(listener);
}
private void notifyGameStateEvent(GameStateEvent evt) {
listeners.forEach(listener -> listener.onGameStateEvent(evt));
}
private void notifyFlaggedTilesEvent(FlaggedTilesEvent evt) {
listeners.forEach(listener -> listener.onFlaggedTilesEvent(evt));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
@ -172,11 +189,21 @@ public class Board extends JPanel {
if (tile.isFlagged()) {
tile.setFlagged(false);
flaggedTiles--;
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
}
// Test if the game is won or lost
if (tile.isMine()) gameState = GameState.LOST;
else if (mines == activeTiles) gameState = GameState.WON;
if (tile.isMine()) {
gameState = GameState.LOST;
repaint();
GameStateEvent evt = new GameStateEvent(this, gameState);
notifyGameStateEvent(evt);
} else if (mines == activeTiles) {
gameState = GameState.WON;
repaint();
GameStateEvent evt = new GameStateEvent(this, gameState);
notifyGameStateEvent(evt);
}
// Touch surrounding tiles when there are zero surrounding mines
else if (tile.getSurroundingMines() == 0)
@ -198,6 +225,7 @@ public class Board extends JPanel {
tile.setFlagged(true);
flaggedTiles++;
}
notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
repaintTile(n, m);
}
}

View File

@ -0,0 +1,63 @@
package dev.kske.minesweeper;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
/**
* Project: <strong>Minesweeper</strong><br>
* File: <strong>CustomDialog.java</strong><br>
* Created: <strong>03.04.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class CustomDialog extends JDialog {
private static final long serialVersionUID = -4019516811065781434L;
private final JPanel mcontentPanel = new JPanel();
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
CustomDialog dialog = new CustomDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the dialog.
*/
public CustomDialog() {
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
mcontentPanel.setLayout(new FlowLayout());
mcontentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(mcontentPanel, BorderLayout.CENTER);
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton);
}
}
}
}

View File

@ -0,0 +1,27 @@
package dev.kske.minesweeper;
import java.util.EventObject;
/**
* Project: <strong>Minesweeper</strong><br>
* File: <strong>FlaggedTilesEvent.java</strong><br>
* Created: <strong>03.04.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class FlaggedTilesEvent extends EventObject {
private static final long serialVersionUID = -5809857531886339312L;
private final Board board;
private final int flagged;
public FlaggedTilesEvent(Object source, int flagged) {
super(source);
board = (Board) source;
this.flagged = flagged;
}
public Board getBoard() { return board; }
public int getFlagged() { return flagged; }
}

View File

@ -0,0 +1,14 @@
package dev.kske.minesweeper;
/**
* Project: <strong>Minesweeper</strong><br>
* File: <strong>GameStateListener.java</strong><br>
* Created: <strong>03.04.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public interface GameListener {
void onGameStateEvent(GameStateEvent evt);
void onFlaggedTilesEvent(FlaggedTilesEvent evt);
}

View File

@ -0,0 +1,27 @@
package dev.kske.minesweeper;
import java.util.EventObject;
/**
* Project: <strong>Minesweeper</strong><br>
* File: <strong>GameStateEvent.java</strong><br>
* Created: <strong>03.04.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class GameStateEvent extends EventObject {
private static final long serialVersionUID = -966111253980213845L;
private final Board board;
private final GameState gameState;
public GameStateEvent(Object source, GameState gameState) {
super(source);
board = (Board) source;
this.gameState = gameState;
}
public Board getBoard() { return board; }
public GameState getGameState() { return gameState; }
}

View File

@ -2,14 +2,18 @@ package dev.kske.minesweeper;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
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;
/**
* Project: <strong>Minesweeper</strong><br>
@ -68,9 +72,38 @@ public class Minesweeper {
mframe.getContentPane().setLayout(new BorderLayout(0, 0));
mframe.getContentPane().add(board, BorderLayout.CENTER);
JPanel headerPanel = new JPanel();
mframe.getContentPane().add(headerPanel, BorderLayout.NORTH);
headerPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
JLabel lblRemainingMines = new JLabel("Remaining Mines:");
lblRemainingMines.setHorizontalAlignment(SwingConstants.LEFT);
headerPanel.add(lblRemainingMines);
board.registerGameListener(new GameListener() {
@Override
public void onGameStateEvent(GameStateEvent evt) {
switch (evt.getGameState()) {
case LOST:
JOptionPane.showMessageDialog(mframe, "Game lost!");
break;
case WON:
JOptionPane.showMessageDialog(mframe, "Game won!");
}
}
@Override
public void onFlaggedTilesEvent(FlaggedTilesEvent evt) {
lblRemainingMines.setText("Remaining Mines: " + (evt.getBoard().getMines() - evt.getFlagged()));
mframe.pack();
}
});
JButton btnRestart = new JButton("Restart");
headerPanel.add(btnRestart);
btnRestart.addActionListener((evt) -> board.reset());
mframe.getContentPane().add(btnRestart, BorderLayout.NORTH);
mframe.pack();
}