Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Mine Sweeper

For this recipe, you will be implementing a simplified version of the
[Mine Sweeper](https://en.wikipedia.org/wiki/Minesweeper_(video_game)) game.

The purpose of this exercise is to introduce you to *functional programming*
aspects of Java introduced in Java 8. Specifically, it will cover:

- [Lambda Expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
- [Method References](https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html)

To complete the recipe, please follow all the instructions laid out in
MineSweeper.java.
132 changes: 132 additions & 0 deletions src/org/jointheleague/level4/minesweeper/MineSweeper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.jointheleague.level4.minesweeper;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.Optional;
import java.util.Random;
import java.util.stream.IntStream;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

/**
* Implement the Mine Sweeper game by following the instructions in the
* comments. All instructions are marked with "TODO".
*/
public class MineSweeper {
private static final int WIDTH = 10;
private static final int HEIGHT = 15;
private static final int CELL_SIZE = 20;
private static final int NUM_MINES = 15;

final JFrame frame = new JFrame();
private final JButton[][] buttons = new JButton[HEIGHT][WIDTH];
private final Random rng = new Random();
private Optional<boolean[][]> mines = Optional.empty();
private int numCellsRemaining;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the number of cells that do not have a mine and has not yet been opened. The name is not clear and can be misunderstood to mean the number of cells not yet opened, including cells with bombs. It is not clear what this field is used for. All we know is that it is decremented (line 106).


/**
* Initializes:
* 1. The `mines` variable with `NUM_MINES` randomly distributed mines
* 2. The `numCellsRemaining` variable to the number of non-mine
* cells (`WIDTH` * `HEIGHT` - `NUM_MINES`).
*
* @param firstCellX X-index of first cell opened. This cannot be a mine.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually avoid x and y and use row and column (or row and col, or r and c). This avoids the confusion about whether rows corresponds to y or x.

* @param firstCellY Y-index of first cell opened. This cannot be a mine.
*/
private void initializeMines(int firstCellX, int firstCellY) {
// TODO fill in
// Hint, use `Optional.of(...)` to create a non-empty `Optional`.
}

/**
* Inspects a given cell, and count the number of neighboring cells that
* are mines.
*
* @param x X-index of cell to inspect.
* @param y Y-index of cell to inspect.
* @return The number of neighboring cells that are mines (0-8).
*/
private Integer getNeighboringMinesCount(int x, int y) {
// TODO fill in
return null;
}

/**
* Resets the game by:
* 1. Setting the `mines` variable back to empty.
* 2. Clearing the button texts, and setting button states to enabled.
*
* @param unused Just here so that method can be passed as ActionListener.
*/
private void resetGame(Object unused) {
// TODO fill in
}

private void createAndShowFrame() {
final JMenuItem resetMenuItem = new JMenuItem("Reset");
resetMenuItem.addActionListener(null); // TODO replace null with method reference that resets the game

final JMenu gameMenu = new JMenu("Game");
gameMenu.add(resetMenuItem);

final JMenuBar menuBar = new JMenuBar();
menuBar.add(gameMenu);

final JPanel controlPanel = new JPanel();
final JButton resetButton = new JButton("Reset");
resetButton.addActionListener(null); // TODO replace null with method reference that resets the game
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TODO is actually part of the assignment.

controlPanel.add(resetButton);

final JPanel gameBoardPanel = new JPanel();
gameBoardPanel.setSize(WIDTH * CELL_SIZE, HEIGHT * CELL_SIZE);
gameBoardPanel.setBackground(Color.WHITE);
gameBoardPanel.setLayout(new GridLayout(HEIGHT, WIDTH));
IntStream.range(0, HEIGHT).forEach(y ->
IntStream.range(0, WIDTH).forEach(x -> {
// This code loops through the X and Y indexes,
// creating a button for each cell.
final JButton b = new JButton();
buttons[y][x] = b;
// When the cell button is pressed, it should:
// 1. Initializes the mines if it is not yet initialized.
// 2. If the button is a mine:
// - Change the button text to an "X"
// - Display "You Lose" in a dialog box
// Otherwise:
// - Change the button text to the number of neighboring
// cells are mines.
// - Decrement `numCellsRemaining`
// - If all cells are open, display "You Win" in a dialog box
// - Extra credit: If the number of neighboring cells is 0,
// automatically open all neighboring cells
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to flag a bomb? Should it be extra credit?

b.addActionListener(null); // TODO replace null with lambda expression
gameBoardPanel.add(b);
})
);

final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(WIDTH * CELL_SIZE, (HEIGHT + 1) * CELL_SIZE + 27);
frame.setLayout(new BorderLayout());
frame.setResizable(false);
frame.setJMenuBar(menuBar);
frame.add(gameBoardPanel, BorderLayout.CENTER);
frame.add(controlPanel, BorderLayout.PAGE_END);

frame.setVisible(true);
}

public static void main(String[] args) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
final MineSweeper mineSweeper = new MineSweeper();
SwingUtilities.invokeLater(mineSweeper::createAndShowFrame);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests so that the students can test their code as they progress. This gets them used to TDD and gives them a few carrots along the way.