CPSC 124 Introduction to Programming Spring 2024

Project 1
Minesweeper

Muddiest Points Due: Thu 2/29 at 10pm
Pseudocode Due: Mon 3/4 at noon
Project Due: Fri 3/15 at noon


Introduction

The programming projects are an opportunity for you to work on a larger program, where there are more pieces to bring together. Unlike the labs, you have several weeks to complete this project — but this project is larger than the lab programs, so start early! There will not be a new lab assignment on 3/12 so there will be time during lab to work on the project, but this is only a few days before it is due so you should not wait until then to get started.

Collaboration

Labs and projects are for practice and learning. While it can be very productive to work on problems with your peers, it is also easy to underestimate how much you yourself understand and can do in such situations — so often something looks easy when someone else does it! With this in mind, you should always make the first attempt on a problem or programming task yourself using only the resources provided for the course (textbook, slides and examples posted on the schedule page, other resources linked on the course webpages). After that point, you are encouraged to come to office hours and/or go to Teaching Fellows. You may not collaboratively write solutions or code, and you may not copy solutions or code written by others, even if you contributed ideas.

You can discuss specific exercises with other students in general terms — such as how you might get started on that problem, or how or when to use various programming constructs, or strategies for debugging — but how to use a particular programming construct to solve a specific problem or debugging a particular program should only be discussed in office hours or with the Teaching Fellows.


Setup

Remember that you will need to compile and run your program(s) using jfxc and jfx, respectively, instead of javac and java.


Overview and Requirements

In this project you will be writing a somewhat simplified version of the Minesweeper game. The object of Minesweeper is to identify the mines hidden in a grid of squares — if the player uncovers a square with a mine, the game is over; otherwise, the number of mines in adjacent squares is revealed. The player can then use this information to deduce the locations of the mines. See the Wikipedia entry on Minesweeper for more information on the game.

Compared to the real game, your program will have several simplifications:

To see how your program should work, try out the demo: (type the commandline in the terminal in VS Code)

  jfx -jar /classes/cs124/demos/minesweeper.jar

Move the yellow square (the current position) using the arrow keys (make sure the mouse is within the program's window before you start pressing keys); press the space bar to uncover the square at the current position.

Program Specifications

Your task is to write a game of Minesweeper that works like the demo — the player moves the current position around, uncovering squares until either all of the squares without a mine have been uncovered or a mine is uncovered. Some specific details:

You are free to customize the program's graphics (colors, fonts, etc) as long as the following are met:

You should also make sure that your program doesn't crash or behave badly if the user does something unexpected. This includes making sure that the current position doesn't move past the boundaries of the board — for example, if the current position is in column 0, pressing the left arrow should have no effect.

Implementation

To keep track of the necessary information in order to play the game, you will need to have several variables:

Each of the 2D arrays should have 10 rows and 20 columns.

(You may need additional variables for loops or other things.)

Programming Style

As with labs, you should follow the standard conventions for indentation, line breaks, naming, and comments. Using autoformat will take care of most of the formatting considerations, though you still need to put in blank lines yourself in order to visually group related statements together and separate statements dealing with separate tasks. Remember to include enough in your variable names to identify what they are for and to distinguish similar variables each other, and to comment your variable declarations if there is additional relevant information not apparent from the variable name.

In addition, you should include comments identifying what is accomplished by chunks of code. (If you write your code under the relevant pseudocode comments that you develop for the pseudocode exercises, you'll have this taken care of.) This isn't about explaining every single line of code, but rather making it easier to get an overview of your program and to understand the tasks that different groups of statements are accomplishing.

Your code should be reasonably compact and elegant, meaning that your program is not significantly longer or more complex than it needs to be. One important component of this is that you use loops when loops are appropriate — achieiving repetition by copying-and-pasting code is not elegant!

Extra Credit

There are lots of possibilities for extra credit — start early so you have time to try some of them! Some possibilities include:

The tags "small", "medium", and "large" are meant to give some idea of the level of effort involved. (The "large" items are significantly more work.) More involved options and more elegant solutions will earn more extra credit. (The chief things to be concerned about are unnecessarily complex solutions, and unnecessary repeated code.) A maximum of 15 points (out of 100 for the project) of extra credit can be earned. If you plan to tackle a lot of extra credit or have an idea for something not listed, come discuss your plans with me.


Exercises

Work through these in order.

Muddiest Points

Stepwise Refinement and Pseudocode

This is a larger program with a number of different components, so it is important to make sure you have a plan before you start writing code. Use the program development strategy that has been discussed in class (and which you have been using in the labs) — write out broad steps in English, then a bit at a time transform those steps into smaller steps with program-like structures (the order of steps should be clear, and use language associated with the making choices and repetition patterns discussed in class). To get you started, here's the first very broad level of pseudocode:

// set up the game
// play the game

"Set up the game" covers everything that needs to be done before the player starts playing — if you think of the demo, it covers everything that happens before you press a key for the first time. Properly initializing the variables in the program is a major part of the setup. (See the "Implementation" section above for important variables that you will need to have.) "Play the game" covers everything once the user starts pressing keys. Between the two steps, the entire program's functionality is covered.

Now, proceed with stepwise refinement — for each broad step, think about what it entails in a little more detail. Also identify what the main flow of control is within that step — does it involve a series of smaller steps, or repetition, or making a choice? That should then be reflected in the structure of your pseudocode, for example:

// set up the game

// play the game
// -- repeat until the game is over
// -- .. get the user's key press
// -- .. handle the user's key press
// -- display win or lose message

(Because you will eventually transfer this to your program and autoformat takes out extra spaces, keep things organized by adding dashes to visually indicate when things are substeps of larger tasks and dots to indicate containment within control structures (loop bodies, bodies of if branches).)

At each step, check for the key elements of pseudocode:

Continue breaking down tasks until they are small enough. This is a bit vague, and there isn't a firm right or wrong answer, but the idea is that you've gotten down to specific and self-contained tasks which are straightforward to translate into Java because they utilize a common or familiar pattern or would only take a few lines of code.

Technical Details — Drawing and User Input

You can draw the game board by going through each slot of the 10x20 grid and drawing the corresponding square in the drawing window — use the information stored in that slot in each of the two arrays to determine how to draw the square (covered or uncovered, number of mines or bomb). You can use fillRect to draw the square (and strokeRect to draw an outline around it, to distinguish one square from another), however, you will need to know the position of the upper left corner of each rectangle in order to draw it. You can work out a formula for converting from the row and column of the grid cell to the y and x coordinates for the rectangle (keep in mind that the x coordinate corresponds to the column and the y coordinate corresponds to the row — this is easy to mix up!), but a simpler option is to treat both the row and column of the grid cell and the x and y coordinates of the rectangle as things that change in the loops and initialize/update them accordingly. (The ColorSpots example from class illustrates this — i is the counter going through the array indexes and x is the x coordinate for the current oval.)

Your program will need to repeatedly get input specifying the player's next move. Since this is a graphical program, you won't use Scanner; instead, the provided Minesweeper template includes getKeyCode() to support getting the user's key presses. (Normally GUIs utilize what is known as event-driven programming, but that is beyond the scope of this course, so getKeyCode() is a workaround.)

Like the Scanner operations, call getKeyCode() when you want user input; it will wait until a key is pressed and then return a value indicating which key was the one pressed. As with Scanner, you'll probably want to store that value in a variable so you can work with it:

  KeyCode key = getKeyCode();

Then, to determine what key was pressed:

  if ( key == KeyCode.LEFT ) {     // left arrow pressed
    ...
  }

Checking for the other possibilities (KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN, or KeyCode.SPACE) is similiar.

(If you do the "flag" option for extra credit, you'll need to check another key: KeyCode.F)

Finally, Minesweeper

Hint: The game board changes as the user plays the game — the current position moves, squares are uncovered, etc. There are a couple of ways to handle this, but the easiest is to just redraw the entire board each time there is a change. (This is a better strategy than trying to redraw just the parts that have changed.)


Handin and Grading

Don't forget to hand in your work when you are done!

As with labs, grading will be based on both functionality and style. The expectations for both are given in the "Overview and Specifications" section above.