OOP – 80 course points
This assignment has a CODING component and a REFLECTION. Please read CAREFULLY.
In this assignment, you will use OOP and 2D arrays to create game boards and implement methods according to the rules of the logic puzzle video game, Minesweeper.
Refer to our Programming Assignments FAQ for instructions on how to install VScode, how to use the command line and how to submit your assignments.
Programming
Write 1 coding assignment and submit on Autolab.
- We provide a zip file containing PlayMinesweeper.java.
- For each problem UPDATE and SUBMIT the corresponding file.
Observe the following rules:
- DO NOT add any import statements
- DO NOT add the project statement
- DO NOT change the class name
- DO NOT change the headers of ANY of the given functions
- DO NOT add any new class fields
- DO NOT use System.exit()
- ONLY print the result as specified by each problem. Observe the examples’ output, display only what the problem is asking for.
- DO NOT print other messages, follow the examples for each problem.
- ONLY print the result as specified by each problem. Observe the examples’ output and display only what the problem is asking for.
- DO NOT print other messages; follow the examples for each problem.
PlayMinesweeper
Start your assignment early! You need time to understand the assignment and to answer the many questions that will arise as you read the description and the code provided.
Refer to our Programming Assignments FAQ for instructions on how to install VSCode, how to use the command line and how to submit your assignments.
- See this video on how to import the files into VS Code and how to submit into Autolab.
The assignment has two components:
- Coding (77 points) submitted through Autolab.
- Reflection (3 points) submitted through a form.
- Submit the reflection AFTER you have completed the coding component.
- Be sure to sign in with your RU credentials! (netid@scarletmail.rutgers.edu)
- You cannot resubmit reflections but you can edit your responses before the deadline by clicking the Google Form link, signing in with your netid, and selecting “Edit your response.”
Overview
Minesweeper is a logic puzzle video game featuring a grid of clickable squares with hidden mines scattered throughout. The objective of the game is to open all of the squares in the grid without detonating any mines. Each square displays a number clue that reflects the number of mines neighboring each square. Players can use these number clues for help navigating the minefield — flagging squares they suspect contain mines and opening squares they assume are safe. Be careful not to click on a mine because if you do . . . it is game over!
For this assignment, you are tasked with developing a program that accomplishes the same objectives as and adheres to the rules of Minesweeper.
To accomplish this, you will work with a 2D array of Square objects, each representing an individual game piece and storing information like the square number and the square state.
Implementation
Overview of files provided
- The PlayMinesweeper class contains the methods you will use to create game boards and mimic the rules of the game. You will submit this file to Autolab.
- The Square class contains information about EACH game piece in the grid. Do not edit or submit to Autolab.
- The State class contains information regarding whether each game piece in the grid is open, closed, or flagged. Do not edit or submit to Autolab.
- The GraphicalDriver and TextDriver classes are used to test your methods interactively. Follow the prompts in the terminal or on your screen to use the driver. Feel free to edit this file, as it is provided only to help you test your code. It is not submitted and is not used to grade your code. Do not submit to Autolab.
- In GraphicalDriver, press the number key corresponding with the options listed on the menu to navigate to the next screen. Once on the next screen, follow the prompts accordingly.
- Use TextDriver to test your code first, as it is simpler to use. Once you have a good understanding of the assignment, then you may use the graphic driver.
- Both drivers function the same way – if it works on one driver it will work on the other.
- Multiple input files are included. They store information regarding the specifications to create each game board. You are welcome to create your own input files, as they will not be submitted to Autolab.
PlayMinsweeper.java
- DO NOT add new import statements.
- DO NOT change any of the method’s signatures.
Methods to be implemented by you:
placeMines
In this method, you will update the instance variable, grid, to be a 2D array of Squares with m rows and n columns. Then, you will place mines in the grid according to the specifications given in the input file. Each Square object represents an individual game piece in the grid.
The input file contains the grid size as well as all the mines to be placed on the grid.
To complete this method you will read from the input file:
- Read the first two integers from the input file which refer to the length (m rows) and width (n columns) of the array. The two integers are separated by a space on the first line.
- Create an array of m x n array Squares and update grid to be a reference to the array.
- Read the (i,j)-coordinates representing the location of each mine to place in the grid. These values are given as two integers separated by a space on one line.
- Notice that each Square has a number (the instance variable sqNum).
- Update sqNum at each [i][j] coordinate to -1 to represent a mine.
- Update the instance variable, totalMines, to match the number of mines placed in the grid.
Use the StdIn library to read from a file:
- StdIn.setFile(inputFile) opens a file to be read.
- StdIn.readInt() reads the next integer value from the opened file (whether the value is in the current line or in the next line).
- To read the mines use a while loop to read two integers in each loop iteration. You will also have to use readLine() to read the remaining of the line (you won’t use the value read by readLine()).
while ( !StdIn.isEmpty() ) {
i = StdIn.readInt(); j = StdIn.readInt(); StdIn.readLine();
}
To test, run one of the drivers: GraphicalDriver or TextDriver.
- Select option 1 from the menu in either driver to test individual methods first.
- Note that both drivers will give you the same output (If characters are not appearing properly you need to edit Line #13 in
Collage.java
tofalse
or Line #14 inTextDriver.java
:
Here is the expected output for this method using b1.in.
fillGrid
In this method, you will fill the remaining squares in the grid according to the Minesweeper rules.
In Minesweeper, any square that does not contain a mine is considered a “safe square.” Safe squares have numbers indicating how many mines, if any, border that square.
For this assignment, each Square object in the grid has a corresponding instance variable, sqNum (see Square.java):
- -1 indicates a mine
- 0 indicates a safe square that does not border any mines
- any number greater than 0 indicates a safe square that borders the specified number of mines
To complete this method, traverse the grid, and for each Square, check if sqNum is -1 (we have a mine).
- If this condition is met , increment sqNum for each Square in the 8-block surrounding the mine. This includes the Squares on the top and bottom, left and right, and diagonal from the mine:
When testing your code, run placeMines() followed by fillGrid() in that order. Here is the expected output for this method using b1.in:
openSquare
The objective of Minesweeper is to open all of the safe squares in the grid.
The Square class also contains the state of the square (sqState):
- open: the gamer clicked the square to be opened.
- closed: the gamer hasn’t clicked this square.
- flagged: the gamer flagged this square as a potential mine.
You will simulate this game feature by creating a method that updates the instance variable, sqState, of the Square to be opened and of adjacent Squares according to the Minesweeper rules.
In Minesweeper, a safe square that does not border any mines is considered an “empty square” (i.e., the corresponding sqNum is 0).
Note the following while completing this method:
- When a player opens a safe Square that borders one or more mines, ONLY that square will open.
- When a player opens an empty Square, the adjacent Squares will open in all directions (up and down, left and right, and diagonal) until reaching Squares that contain numbers.
- Flagged Squares are considered unopened and, therefore, can be selected to be opened. If a flagged Square is successfully opened, the flag will be removed from the Square, and the Square will enter an OPEN state. The instance variable, flagCount, is updated to account for the flag that was removed from the grid.
- If a player attempts to open a Square that contains a mine, the game will end.
Note that this method returns TRUE if the Square was successfully opened and FALSE if the Square contains a mine.
To complete this method:
- Check if the selected Square is FLAGGED.
- If this condition is met, decrement flagCount to account for the flag that will be removed from the grid.
- Check if the selected Square contains a mine.
- If this condition is met, return false.
- Update sqState to OPEN the selected Square.
- Check if the selected Square is an empty Square (i.e., if sqNum is 0).
- If this condition is met, use recursion to open the adjacent empty Squares in all directions (up and down, left and right, and diagonal):
- For a Square in EACH direction, check if the Square is unopened.
- If this condition is met, call openSquare() using the row-coordinate and column-coordinate of the checked Square.
- For a Square in EACH direction, check if the Square is unopened.
- If this condition is met, use recursion to open the adjacent empty Squares in all directions (up and down, left and right, and diagonal):
- Return TRUE to indicate that the Square was successfully opened.
Note that the method will pass in the row-coordinate and column-coordinate of the selected Square for you to use. Remember that row and column indices in a 2D array begin at 0.
Note that the directional component of the recursive algorithm is the same as the one in fillGrid(). To check if a Square in any direction is unopened, use the same strategy as you did in fillGrid() when accessing Squares in the 8-block surrounding a mine. For the recursive step, be sure to call openSquare() using the row-coordinate and column-coordinate of the Square you CHECKED.
When testing your code, run placeMines() and fillGrid() in that order before running this method. Here is the expected output for this method using b1.in and selecting the Square at coordinates (3,0):
placeFlag
In Minesweeper, as players use the number clues to solve the game, they can place flags on squares they suspect contain mines. You will simulate this game feature by creating a method that updates the instance variable, sqState, of the Square selected to be flagged.
Note the following while completing this method:
- Flags CANNOT be placed on open Squares.
- If the Square selected to be flagged already contains a flag, the flag will be removed from the Square, and the Square will return to a CLOSED state.
- Every time a flag is added or removed from the grid, the instance variable, flagCount, is updated accordingly.
To complete this method:
- Check if the selected Square is FLAGGED.
- If this condition is met, remove the flag from the Square by updating sqState to be CLOSED.
- Decrement flagCount to account for the flag that was removed from the grid.
- Check if the selected Square is CLOSED.
- If this condition is met, add the flag to the Square by updating sqState to be FLAGGED.
- Increment flagCount to account for the flag that was added to the grid.
Note that the method will pass in the row-coordinate and column-coordinate of the selected Square for you to use. Remember that row and column indices in a 2D array begin at 0.
When testing your code, run placeMines() and fillGrid() in that order before running this method. Here is the expected output for this method using b1.in and selecting the square at coordinates (1,1):
checkWinCondition
To win a game of Minesweeper, a player must open all of the safe squares in the grid without detonating a mine. In this method, you will check whether a player has won their game of PlayMinesweeper according to this condition.
Note that this method returns TRUE if the player opened all of the safe Squares in the grid and FALSE otherwise.
To complete this method:
- Traverse the grid, and for each Square, check if:
- the Square is a safe Square AND
- the Square is unopened.
- If both conditions are met, return false to indicate that an unopened safe Square remains in the grid.
- Otherwise, return true to indicate that the player has opened all of the safe Squares in the grid.
Note that the outcome of this method will vary depending on your progress in the game. To produce the result below, run placeMines(), fillGrid(), and openSquare() on the Square at (3,0) in that order before running this method. Here is the expected output of this method using b1.in immediately after opening the Square at (3,0):
Note that the game has not been won yet because there remain unopened safe Squares in the grid.
chooseDifficulty
The next two methods work together to simulate a more realistic Minesweeper experience by generating random game boards for players to interact with. In this method, you will set up game boards by updating the instance variable, grid, according to the criteria of the Minesweeper difficulty levels.
Note that the method will pass in the difficulty level for you to use.
To complete this method:
- Check if the difficulty input parameter level is “Beginner.”
- If this condition is met, update the grid to be an 8 x 8 array of Squares.
- Set the instance variable, totalMines, to 10 to indicate the number of mines that will be placed in the grid.
- Check if the difficulty input parameter level is “Intermediate.”
- If this condition is met, update the grid to be a 16 x 16 array of Squares.
- Set the instance variable, totalMines, to 40 to indicate the number of mines that will be placed in the grid.
- Check if the difficulty input parameter level is “Advanced.”
- If this condition is met, update the grid to be a 30 x 16 array of Squares.
- Set the instance variable, totalMines, to 99 to indicate the number of mines that will be placed in the grid.
Here is the expected output of this method selecting the “Beginner” difficulty level:
playRandom (challenge for the bored – worth 0 points)
This method will be tested by Autolab to give you feedback but it is worth 0 points.
To play the full game, with random boards, you need this method.
In Minesweeper, the first click is always safe (i.e., the first square a player clicks will never contain a mine). You will simulate this game feature by creating a method that randomly places mines in the game board after the player makes their first click.
Note that the method will pass in a difficulty level and the row-coordinate and column-coordinate of the player’s first click.
To complete this method:
- If the difficulty input parameter level is “Beginner,” place 10 mines in the grid.
- If the difficulty input parameter level is “Intermediate,” place 40 mines in the grid.
- If the difficulty input parameter level is “Advanced,” place 99 mines in the grid.
- To place a mine in the grid:
- Generate a row-coordinate and column-coordinate using the StdRandom class.
- Check if the randomized coordinate pair:
- DOES NOT equal the coordinates of the player’s first click.
- DOES NOT contain a mine.
- If both conditions are met, update sqNum to -1 to represent a mine.
- Repeat this process until the designated number of mines have been placed in the grid according to the criteria above.
Note that the outcome of this method will vary as mines are placed in the grid randomly. When testing your code, run chooseDifficulty followed by playRandom in that order.
Here is an example of the expected output of this method in TextDriver selecting the “Beginner” difficulty level and making the first click at coordinates (2,4):
Here is an example of the expected output of this method in GraphicalDriver selecting the “Beginner” difficulty level and making the first click at coordinates (2,4):
Note that the first image is produced after a player makes their first click. The location of the mines and the sqNum of safe Squares in the grid are revealed. A player can click anywhere on the grid or press ‘Enter’ on their keyboard to produce the second image where all Squares are concealed except for the Square where they made their first click.
At this point, you can relaunch either driver and select option 2 to play an entire game of your very own PlayMinesweeper. Have fun!
How to use GraphicalDriver to play a full game of PlayMinesweeper:
- ** Note that if the flag in the top left corner is red, you are in flagging mode, and if the flag is black, you are in opening mode
- Select option 2 from the menu to play a full game.
- Select the corresponding number keys on your keyboard to choose your difficulty level.
- To open a Square, click on it.
- To flag a Square, press ‘F’ on your keyboard and click the Square you want to flag.
- To remove a flag from a Square, press ‘F’ on your keyboard and click the Square you want to deflag.
- To open a Square with a flag, remove the flag before clicking on the Square to open it.
Implementation Notes
- YOU MAY only update the methods with the WRITE YOUR CODE HERE line.
- COMMENT all print statements you have written from PlayMinesweeper.java
- DO NOT add any instance variables to the PlayMinesweeper class.
- DO NOT add any public methods to the PlayMinesweeper class.
- DO NOT add/rename the project or package statements.
- DO NOT change the PlayMinesweeper class name.
- YOU MAY add private methods to the PlayMinesweeper class.
- YOU MAY use any of the libraries provided in the zip file.
- DO NOT use System.exit()
VSCode Extensions
You can install VSCode extension packs for Java. Take a look at this tutorial. We suggest:
Importing VSCode Project
- Download Assignment8.zip from Autolab Attachments.
- Unzip the file by double clicking.
- Open VSCode
- Import the folder to a workspace through File > Open Folder
Executing and Debugging
- You can run your program through VSCode or you can use the Terminal to compile and execute. We suggest running through VSCode because it will give you the option to debug.
- How to debug your code
- If you choose the Terminal:
- first navigate to PlayMinesweeper directory/folder
- to compile: javac *.java
- to execute: java GraphicalDriver
- first navigate to PlayMinesweeper directory/folder
By Jessica de Brito and Jeremy Hui
Before submission
Collaboration policy. Read our collaboration policy here.
Submitting the assignment
Submit Minesweeper.java separately via the web submission system called Autolab. To do this, click the Assignments link from the course website; click the Submit link for that assignment.
Getting help
If anything is unclear, don’t hesitate to drop by office hours or post a question on Piazza.
- Find instructors office hours here
- Find tutors office hours on Canvas -> Tutoring
- Find head TAs office hours here
- In addition to office hours we have the Coding and Social Lounge (CSL) , a community space staffed with lab assistants which are undergraduate students further along the CS major to answer questions.