633 lines
20 KiB
Java
633 lines
20 KiB
Java
--------------------------------- START of Main.java ---------------------------------
|
|
//By xykmz. Enjoy!
|
|
|
|
import java.util.Scanner;
|
|
|
|
public class Main {
|
|
|
|
static int intErrorTrap (int x, int y){
|
|
|
|
int max, min;
|
|
|
|
if (x < y) {
|
|
min = x;
|
|
max = y;
|
|
} else {
|
|
min = y;
|
|
max = x;
|
|
}
|
|
|
|
int input;
|
|
boolean loopEnd;
|
|
|
|
do {
|
|
|
|
System.out.println("Please enter an integer between " + min + " to " + max + ".");
|
|
Scanner userInput = new Scanner(System.in); //Player inputs a guess
|
|
|
|
try
|
|
{
|
|
input = userInput.nextInt();
|
|
|
|
if(input > max) //Input is too high
|
|
{
|
|
loopEnd = false;
|
|
System.out.println("Input is invalid.");
|
|
return -1;
|
|
}
|
|
|
|
else if(input < min) //Input is too low
|
|
{
|
|
loopEnd = false;
|
|
System.out.println("Input is invalid.");
|
|
return -1;
|
|
}
|
|
|
|
else //Input is within acceptable range
|
|
{
|
|
loopEnd = true;
|
|
System.out.println(input + " is a valid input.");
|
|
return input;
|
|
|
|
}
|
|
}
|
|
|
|
catch (Exception e)
|
|
{
|
|
loopEnd = false;
|
|
userInput.next();
|
|
System.out.println("Input is invalid.");
|
|
return 0;
|
|
}
|
|
|
|
} while (loopEnd == false);
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
System.out.println ("Enter width.");
|
|
int x = intErrorTrap (0,60);
|
|
|
|
System.out.println ("Enter height.");
|
|
int y = intErrorTrap (0,30);
|
|
|
|
System.out.println ("Enter difficulty.");
|
|
int d = intErrorTrap (0,100);
|
|
|
|
new Minesweeper(x, y, d); //Suggested: (60, 30, 15)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------- END of Main.java ---------------------------------
|
|
|
|
//--------------------------------- START of Cell.java ---------------------------------
|
|
|
|
|
|
|
|
public class Cell{ //This entire class is quite self-explanatory. All we're really doing is setting booleans.
|
|
|
|
private boolean isMine, isFlagged, isCovered;
|
|
private int number;
|
|
|
|
public Cell(){
|
|
isMine = false;
|
|
isFlagged = false;
|
|
isCovered = true;
|
|
number = 0;
|
|
}
|
|
|
|
public void flag(){
|
|
isFlagged = true;
|
|
}
|
|
|
|
public void unflag(){
|
|
isFlagged = false;
|
|
}
|
|
|
|
public void setMine(){
|
|
isMine = true;
|
|
}
|
|
|
|
public boolean isMine(){
|
|
return isMine;
|
|
}
|
|
|
|
public void reveal(){
|
|
isCovered = false;
|
|
}
|
|
|
|
public void setNumber(int i){ //Set the number of the cell
|
|
number = i;
|
|
}
|
|
|
|
public int getNumber(){ //Request the program for the number of the cell
|
|
return number;
|
|
}
|
|
|
|
public boolean isFlagged(){
|
|
return isFlagged;
|
|
}
|
|
|
|
public boolean isCovered(){
|
|
return isCovered;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//--------------------------------- END of Cell.java ---------------------------------
|
|
|
|
//--------------------------------- START of Board.java ---------------------------------
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Dimension;
|
|
import java.awt.Graphics;
|
|
import javax.swing.JPanel;
|
|
|
|
public class Board extends JPanel{
|
|
|
|
private static final long serialVersionUID = 1L; //Guarantees consistent serialVersionUID value across different java compiler implementations,
|
|
//Auto-generated value might screw things up
|
|
|
|
private Minesweeper mine;
|
|
private Cell[][] cells;
|
|
|
|
|
|
public void paintComponent(Graphics g){
|
|
|
|
cells = mine.getCells();
|
|
|
|
for (int i = 0; i < mine.getx(); i++){
|
|
|
|
for (int j = 0; j < mine.gety(); j++){
|
|
|
|
Cell current = cells[i][j];
|
|
|
|
|
|
//Flagged cells
|
|
if (current.isFlagged()){
|
|
|
|
if (current.isMine() && mine.isFinished()){
|
|
|
|
g.setColor(Color.ORANGE); //Let's the player know which mines they got right when the game is finished.
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
|
|
g.drawLine(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.drawLine(i * 20, j * 20 + 20, i * 20 + 20, j * 20);
|
|
}
|
|
else if (mine.isFinished()){ //Shows cells that the player incorrectly identified as mines.
|
|
g.setColor(Color.YELLOW);
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
}
|
|
else{
|
|
g.setColor(Color.GREEN); //Flagging a mine.
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
}
|
|
}
|
|
|
|
//Unflagged cells
|
|
else if (current.isCovered()){ //Covered cells
|
|
g.setColor(Color.DARK_GRAY);
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
}
|
|
else if (current.isMine()){ //Incorrect cells are shown when the game is over.=
|
|
g.setColor(Color.RED);
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
g.drawLine(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.drawLine(i * 20, j * 20 + 20, i * 20 + 20, j * 20);
|
|
}
|
|
else{ //Empty cells or numbered cells
|
|
g.setColor(Color.LIGHT_GRAY);
|
|
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
g.setColor(Color.BLACK);
|
|
}
|
|
|
|
//The following part is very self explanatory - drawing the numbers.
|
|
//Not very interesting work.
|
|
//Not a fun time.
|
|
//Rating: 0/10. Would not recommend.
|
|
|
|
if (!current.isCovered()){
|
|
if (current.getNumber() == 1){
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
}
|
|
else if (current.getNumber() == 2){
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
|
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
|
}
|
|
else if (current.getNumber() == 3){
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
|
}
|
|
else if (current.getNumber() == 4){
|
|
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
}
|
|
else if (current.getNumber() == 5){
|
|
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
|
}
|
|
else if (current.getNumber() == 6){
|
|
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
|
}
|
|
else if (current.getNumber() == 7){
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
}
|
|
else if (current.getNumber() == 8){
|
|
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
|
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
|
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
|
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
|
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
|
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
|
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
|
}
|
|
}
|
|
g.setColor(Color.BLACK);
|
|
g.drawRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Board(Minesweeper m){ //Creating a new game so we can draw a board for it
|
|
mine = m;
|
|
cells = mine.getCells();
|
|
|
|
addMouseListener(new Actions(mine));
|
|
|
|
setPreferredSize(new Dimension(mine.getx() * 20, mine.gety() * 20));
|
|
}
|
|
|
|
}
|
|
|
|
//--------------------------------- END of Board.java ---------------------------------
|
|
|
|
//--------------------------------- START of Actions.java ---------------------------------
|
|
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
|
|
public class Actions implements ActionListener, MouseListener{
|
|
|
|
private Minesweeper mine;
|
|
|
|
//These following four are not important. We simply tell the machine to pay no mind when mouse is pressed, released, etc.
|
|
//If these weren't here the computer would freak out and panic over what to do because no instructions were given.
|
|
|
|
public void mouseEntered(MouseEvent e){
|
|
|
|
}
|
|
|
|
public void mouseExited(MouseEvent e){
|
|
|
|
}
|
|
|
|
public void mousePressed(MouseEvent e){
|
|
|
|
}
|
|
|
|
public void mouseReleased(MouseEvent e){
|
|
|
|
}
|
|
|
|
//Where the fun begins
|
|
|
|
public Actions(Minesweeper m){
|
|
|
|
mine = m;
|
|
}
|
|
|
|
//Any time an action is performed, redraw the board and keep it up to date.
|
|
public void actionPerformed(ActionEvent e){
|
|
|
|
mine.reset();
|
|
|
|
mine.refresh();
|
|
}
|
|
|
|
//Mouse clicky clicky
|
|
public void mouseClicked(MouseEvent e){
|
|
|
|
//Left click - opens mine
|
|
if (e.getButton() == 1)
|
|
{
|
|
int x = e.getX() / 20;
|
|
int y = e.getY() / 20;
|
|
|
|
mine.select(x, y);
|
|
}
|
|
|
|
//Right click - marks mine
|
|
if (e.getButton() == 3)
|
|
{
|
|
int x = e.getX() / 20;
|
|
int y = e.getY() / 20;
|
|
|
|
mine.mark(x, y);
|
|
}
|
|
|
|
|
|
mine.refresh(); //Gotta keep it fresh
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//--------------------------------- END of Actions.java ---------------------------------
|
|
|
|
//--------------------------------- START of Minesweeper.java ---------------------------------
|
|
|
|
import java.awt.BorderLayout;
|
|
import java.util.Random;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JOptionPane;
|
|
|
|
public class Minesweeper extends JFrame
|
|
{
|
|
private static final long serialVersionUID = 1L;
|
|
private int width, height;
|
|
private int difficulty;
|
|
private Cell[][] cells;
|
|
private Board board;
|
|
private JButton reset;
|
|
private boolean finished;
|
|
|
|
|
|
public void select(int x, int y){ //Select a mine on the board
|
|
|
|
if (cells[x][y].isFlagged()) //Is the mine flagged?
|
|
return;
|
|
|
|
cells[x][y].reveal(); //Reveal the cell
|
|
resetMarks(); //Reset marks and redraw board
|
|
refresh();
|
|
|
|
if (cells[x][y].isMine()) //If a mine is revealed, you lose.
|
|
{
|
|
lose();
|
|
}
|
|
else if (won()) //If the game has been won, you win. Hahahahahaha.
|
|
{
|
|
win();
|
|
}
|
|
}
|
|
|
|
private void setNumbers(){ //For each cell, count the amount of mines in surrounding squares.
|
|
//Because the board is modeled as a 2D array, this is relatively easy - simply check the surrounding addresses for mines.
|
|
//If there's a mine, add to the count.
|
|
|
|
for (int i = 0; i < width; i++){
|
|
|
|
for (int j = 0; j < height; j++){
|
|
|
|
int count = 0;
|
|
|
|
if (i > 0 && j > 0 && cells[i - 1][j - 1].isMine())
|
|
count++;
|
|
|
|
if (j > 0 && cells[i][j - 1].isMine())
|
|
count++;
|
|
|
|
if (i < width - 1 && j > 0 && cells[i + 1][j - 1].isMine())
|
|
count++;
|
|
|
|
if (i > 0 && cells[i - 1][j].isMine())
|
|
count++;
|
|
|
|
if (i < width - 1 && cells[i + 1][j].isMine())
|
|
count++;
|
|
|
|
if (i > 0 && j < height - 1 && cells[i - 1][j + 1].isMine())
|
|
count++;
|
|
|
|
if (j < height - 1 && cells[i] [j + 1].isMine())
|
|
count++;
|
|
|
|
if (i < width - 1 && j < height - 1 && cells[i + 1][j + 1].isMine())
|
|
count++;
|
|
|
|
cells[i][j].setNumber(count);
|
|
|
|
|
|
if (cells[i][j].isMine())
|
|
cells[i][j].setNumber(-1);
|
|
|
|
|
|
if (cells[i][j].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < width; i++){ //This is for the beginning of the game.
|
|
//If the 8 cells around certain cell have no mines beside them (hence getNumber() = 0) beside them, this cell is empty.
|
|
|
|
for (int j = 0; j < height; j++){
|
|
|
|
if (i > 0 && j > 0 && cells[i - 1][j - 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (j > 0 && cells[i][j - 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (i < width - 1 && j > 0 && cells[i + 1][j - 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (i > 0 && cells[i - 1][j].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (i < width - 1 && cells[i + 1][j].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (i > 0 && j < height - 1 && cells[i - 1][j + 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (j < height - 1 && cells[i][j + 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
|
|
if (i < width - 1 && j < height - 1 && cells[i + 1][j + 1].getNumber() == 0)
|
|
cells[i][j].reveal();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void mark(int x, int y){ //When a player wants to flag/unflag a cell
|
|
|
|
if (cells[x][y].isFlagged()) //If the cell is already flagged, unflag it.
|
|
cells[x][y].unflag();
|
|
|
|
else if (cells[x][y].isCovered()) //If the cell has nothing on it and is covered, flag it.
|
|
cells[x][y].flag();
|
|
|
|
resetMarks();
|
|
}
|
|
|
|
private void resetMarks(){ //If a cell is not covered, then it cannot be flagged.
|
|
//Every time a player does something, this should be called to redraw the board.
|
|
|
|
for (int i = 0; i < width; i++){
|
|
for (int j = 0; j < height; j++){
|
|
|
|
if (!cells[i][j].isCovered())
|
|
cells[i][j].unflag();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public void reset(){ //Reset the positions of the mines on the board
|
|
//If randomly generated number from 0 to 100 is less than the chosen difficulty, a mine is placed down.
|
|
//This will somewhat accurately reflect the mine percentage that the user requested - the more cells, the more accurate.
|
|
|
|
Random random = new Random();
|
|
finished = false;
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
for (int j = 0; j < height; j++) {
|
|
|
|
Cell c = new Cell();
|
|
cells[i][j] = c;
|
|
int r = random.nextInt(100);
|
|
|
|
if (r < difficulty)
|
|
{
|
|
cells[i][j].setMine(); //Put down a mine.
|
|
}
|
|
|
|
}
|
|
}
|
|
setNumbers(); //Set the numbers after mines have been put down.
|
|
}
|
|
|
|
public int getx() {
|
|
return width;
|
|
}
|
|
|
|
public int gety() {
|
|
return height;
|
|
}
|
|
|
|
public Cell[][] getCells() {
|
|
return cells;
|
|
}
|
|
|
|
|
|
public void refresh(){ //Refresh the drawing of the board
|
|
board.repaint();
|
|
}
|
|
|
|
private void win(){ //Winning a game
|
|
finished = true;
|
|
for (int i = 0; i < width; i++)
|
|
{
|
|
for (int j = 0; j < height; j++)
|
|
{
|
|
cells[i][j].reveal();//Reveal all cells
|
|
|
|
if (!cells[i][j].isMine())
|
|
cells[i][j].unflag();
|
|
}
|
|
}
|
|
|
|
refresh();
|
|
JOptionPane.showMessageDialog(null, "Congratulations! You won!"); //Tell the user they won. They probably deserve to know.
|
|
reset();
|
|
}
|
|
|
|
private void lose(){ //Losing a game...basically the same as above.
|
|
finished = true;
|
|
for (int i = 0; i < width; i++)
|
|
{
|
|
for (int j = 0; j < height; j++)
|
|
{
|
|
if (!cells[i][j].isCovered())
|
|
cells[i][j].unflag();
|
|
|
|
cells[i][j].reveal();
|
|
}
|
|
}
|
|
refresh();
|
|
JOptionPane.showMessageDialog(null, "GAME OVER."); //Dialogue window letting the user know that they lost.
|
|
reset();
|
|
}
|
|
|
|
|
|
private boolean won(){ //Check if the game has been won
|
|
for (int i = 0; i < width; i++){
|
|
for (int j = 0; j < height; j++){
|
|
|
|
if (cells[i][j].isCovered() && !cells[i][j].isMine())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
public boolean isFinished(){ //Extremely self-explanatory.
|
|
return finished;
|
|
}
|
|
|
|
public Minesweeper(int x, int y, int d){
|
|
|
|
width = x; //Width of the board
|
|
height = y; //Height of the board
|
|
difficulty = d; //Percentage of mines in the board
|
|
cells = new Cell[width][height];
|
|
|
|
reset(); //Set mines on the board
|
|
|
|
board = new Board(this); //Create new board
|
|
reset = new JButton("Reset"); //Reset button
|
|
|
|
add(board, BorderLayout.CENTER); //Put board in the center
|
|
add(reset, BorderLayout.SOUTH); //IT'S A BUTTON! AND IT WORKS! VERY COOL
|
|
|
|
reset.addActionListener(new Actions(this)); //ActionListener to watch for mouse actions
|
|
|
|
//GUI window settings
|
|
setTitle("Minesweeper");
|
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
setResizable(false);
|
|
pack();
|
|
setVisible(true);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------- END of Minesweeper.java ---------------------------------
|