Table of Contents
=================
* [Minesweeper Demo](#minesweeper-demo)
* [Minesweeper](#minesweeper)
* [Game Driver](#game-driver)
* [Library](#library)
* [User Interface](#user-interface)
* [Menu](#menu)
* [Board](#board)
* [Squares](#squares)
* [Bombs](#bombs)
* [Download](#download)
# Minesweeper Demo
<p align="center"><img src ="images/minesweeper.gif" width = "600px"></p>
# Minesweeper
[![LICENSE](https://img.shields.io/cocoapods/l/AFNetworking.svg)](https://github.com/Hephaest/Minesweeper/blob/master/LICENSE)
[![JDK](https://img.shields.io/badge/JDK-8u202%20-orange.svg)](https://www.oracle.com/technetwork/java/javase/8u202-relnotes-5209339.html)
[![Size](https://img.shields.io/badge/Size-54MB-critical.svg)](https://github.com/Hephaest/Minesweeper/raw/master/download/Minesweeper_64-bit_Windows_Setup.exe)
English | [中文](README_CN.md)
Last updated on `2019/07/08`
The minesweeper has following **functionalities**:
1. Displays an image of a bomb if that square has a bomb on it.
2. Displays the number of bombs in surrounding squares if the player clicks the left mouse otherwise.
3. Works for a board of any size or shape (customisation)
4. Provides several levels of the game.
5. Display a red flag if the player single clicks the right mouse.
6. Display a question mark if the player double clicks the right mouse.
7. Display all bombs and squares with wrong operations if the player fails the game.
8. Display all bombs of squares replacing red flags if the player wins the game.
The source code contains an abstract class and an interface. I have divided my program into 3 parts: `GameDriver`, `Library`, `UserInterface`.
# Game Driver
This part is very simple. The `Driver` class is used to start the game.
The code is shown as follows:
```Java
package GameDriver;
import UserInterface.Menu;
/**
* @author Hephaest
* @since 3/21/2019 8:41 PM
* This class is used to run the minesweeper program.
*/
public class Driver
{
public static void main(String[] Args)
{
// Start the game with a menu.
new Menu("Minesweeper");
}
}
```
# Library
The package `Library` only contains 2 tools. The first one is abstract class `Bomb`, which stores the information about the game board.
The code is shown as follows:
```Java
package Library;
import UserInterface.GameBoard;
/**
* @author Hephaest
* @since 3/21/2019 8:41 PM
* This class is abstract and should be extended to provide the domain specific functionality.
*/
public abstract class Bomb
{
/** The GameBoard instance **/
protected GameBoard board;
/** The height of this GameBoard instance **/
protected int boardHeight;
/** The width of this GameBoard instance **/
protected int boardWidth;
/**
* Create bombs, which can be placed on a GameBoard.
* @param board the GameBoard upon which user clicks on.
*/
public Bomb(GameBoard board)
{
this.board = board;
// Both height and width of the board should remove its padding values.
boardHeight = (board.getHeight() - 20) / 20;
boardWidth = (board.getWidth() - 20) / 20;
}
/**
* A method that is invoked when producing bombs on the game board.
*/
protected abstract void reproduceBomb();
}
```
The second one is `TimeChecker`, an interface to convert milliseconds to a string representation of the corresponding time, is used in `SmartSquare` class.
The code is shown as follows:
```Java
package Library;
/**
* @author Hephaest
* @since 3/21/2019 8:41 PM
* This interface has a static method to convert milliseconds to a string representation of the
* corresponding time.
*/
public interface TimeChecker
{
/**
* This static method could return a string representation of the cost time by the given running time.
* @param time the running time between the game starts and ends.
* @return a string representation of the cost time.
*/
static String calculateTime(long time)
{
int CONVERT_TO_SEC = 1000;
int CONVERT_TO_OTHERS = 60;
int ms = (int) time;
int sec = ms / CONVERT_TO_SEC;
int min = sec / CONVERT_TO_OTHERS; // Seconds convert to minutes.
int hr = min / CONVERT_TO_OTHERS; // Minutes convert to hours.
if (hr == 0)
{
if(min == 0)
{
if (sec == 0)
return ms + " ms";
else
return sec + " sec " + ms % 1000 + " ms";
} else
return min + " min " + sec % CONVERT_TO_OTHERS + " sec " + ms % CONVERT_TO_SEC + " ms";
} else
return hr + " hour " + min % CONVERT_TO_OTHERS + " min " + sec % CONVERT_TO_OTHERS + " sec " + ms % CONVERT_TO_SEC + " ms";
}
}
```
# User Interface
The following UML diagram could help you easier to understand relationships between the following classes:
<p align="center"><img src ="images/bluejScreenshot.png" width = "600px"></p>
## Menu
The `Menu` class provides 4 difficulty options to players: Beginner, Intermediate, Advanced and Custom. Especially for Custom, the program needs the check whether the player's input is valid or not. If the player confirms the option, the progarm starts the timer.
The code is shown as follows:
```Java
package UserInterface;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.regex.Pattern;
/**
* This class inherits from the JFrame class.
* This class implements the methods from ActionListener to respond different click events.
* This class provides 4 options for user to start a new game.
* These 4 options are "Beginner", "Intermediate", "Advanced" and "Custom".
* After clicking "New Game" button, this pop-window is automatically closing.
* @author Hephaest
* @since 3/21/2019 8:41 PM
*/
public class Menu extends JFrame implements ActionListener
{
private JButton start;
private JRadioButton beginner, intermediate, advanced, custom;
private JTextField width, height, mines;
/**
* Create a menu of the given title.
* @param title the title string for the window.
*/
public Menu(String title)
{
// Create a window title.
setTitle(title);
// Create a subtitle
JLabel subtitle = new JLabel("Difficulty");
subtitle.setBounds(100,10,100,20);
add(subtitle);
// Create the "Beginner" radio button.
beginner = new JRadioButton("Beginner");
beginner.setBounds(40,40,150,20);
add(beginner);
// Create the "Beginner" descriptions.
JLabel bDescFirstLine = new JLabel("10 mines");
bDescFirstLine.setBounds(70,60,100,20);
JLabel bDescSecondLine = new JLabel("10 x 10 tile grid");
bDescSecondLine.setBounds(70,80,100,20);
add(bDescFirstLine);
add(bDescSecondLine);
// Create the "Intermediate" radio button
intermediate=new JRadioButton("Intermediate");
intermediate.setBounds(40,100,150,20);
add(intermediate);
// Create the "Intermediate" descriptions.
JLabel iDescFirstLine = new JLabel("40 mines");
iDescFirstLine.setBounds(70,120,100,20);
JLabel iDescSecondLine = new JLabel("16 x 16 tile grid");
iDescSecondLine.setBounds(70,140,100,20);
add(iDescFirstLine);
add(iDescSecondLine);
// Create the "Advanced" radio button
advanced=new JRadioButton("Advanced");
advanced.setBounds(40,160,160,20);
add(advanced);
// Create the "Advanced" descriptions.
JLabel aDescFirstLine = new JLabel("100 mines");
aDescFirstLine.setBounds(70,180,100,20);
JLabel aDescSecondLine = new JLabel("30 x 25 tile grid");
aDescSecondLine.setBounds(70,200,100,20);
add(aDescFirstLine);
add(aDescSecondLine);
// Create the "Custom" radio button
custom = new J