Programming Project 2

This semester you will be writing a program that will be an interactive game, similar to minesweeper. For those students not familiar with the game, a two dimensional grid is presented to a user, which starts off unswept, and contains some number of hidden mines. This blank grid looks like the following:



With such a game, a user would normally click on various tiles, trying to avoid clicking on a mine. The objective is to click on all non-mine tiles. If a mine in clicked, the game is lost and is over. If a non-mine tile is clicked, it will be displayed, either as an integer between one and eight, indicating the number of neighboring mines to that tile, or, if there are no neighboring mines, the tile is marked as viewed, and all of its neighboring empty tiles are also revealed. For example, a player partly through the game may see something like the following:



In the example above, the user has the option of flagging tiles that they think are mines, but this is done with a right-mouse click, rather than a left. The user wins the game when they have revealed every non-mine tile by clicking on it:



This semester you will be building a textual version of the minesweeper game, which is simplified for easier implementation (for example, our games won't have timers or graphical elements). You will have four programming assignments, including this one, which will help you build the game by the end of the semester. Each programming assignment will build on the previous one.

Rather than write this project at once, we will break the project down into several two-week sub-projects that are due throughout the semester. The rest of this document will detail the first such assignment.

PROJECT UPDATES AND CLARIFICATIONS

This first assignment will ask you to write some code that will help you in playing the game later on. You will complete two functions available in the template file for project2_template.py. You should save that template file under the name project2.py.

You will have to do three things for this assignment:

Ideally, you should write your test cases before you write your code. In doing so, your test cases will all initially fail (because you haven't written any code), but that's fine. So, next we're going to explain what the two functions above are supposed to do, and then we'll explain how to format your test cases so you can get credit for them on Marmoset, and how you can run these test cases on code you will write.

The getNeighborLabels function takes as arguments, or already knows the value of, the boardWidth and a current tile called me. You can imagine the user has entered these values, and they are stored in variables called boardWidth and me; you do not need to ask the user to enter these values. In general the tiles of a board are always numbered, starting at zero. For example, on a board with a width of 4 and a height of 3, the tiles would be labeled as:
 0   1   2   3 
 4   5   6   7 
 8   9  10 11

For this function, you will simply be performing the following calculations and storing each value in a string:
me – boardWidth – 1 me – boardWidth me – boardWidth + 1
me – 1 me me + 1
me + boardWidth – 1 me + boardWidth me + boardWidth+ 1

Your function should find all the neighbors of the tile me, and return them as a string with the tiles in sorted order (if you write your algorithm "the easy way," it will be natural for the tiles to be in sorted order). For example, a call to the function with getNeighborLabels(5,0) (here 5 is the boardWidth and 0 is the me argument) would return the string of neighbors "[1, 4, 5, 6]". Each list will start and end with a bracket, and each element of the list will be separated from a previous element by a comma and then a space.

If the board provided is invalid, (i.e. its width is not a natural number), your function should return a string of "invalid board!". You may assume that the me tile will always be an integer, however your method should never return any negative neighbors, as these will be impossible to fit on any board. Note that we don't know if the me tile provided is ever too large, because we do not have the height of the board in this function. You can always assume that the board that would be calling this function provides a valid me tile for this project, and that all arguments are integers. If one of the neighbors has the same value as the me, you should include that in the result. Your result should also NOT have any duplicates - you need to check that you didn't already add a tile like that to the string, before adding it.
Although your function above will work in cases where the me tile is in the middle of the board, it will calculate incorrect values if the tile is along an edge. Therefore, we are going to write another function to verify the labels returned by the function above.

The second function you will write for this project is called verifyNeighbor. This function takes as arguments a boardWidth, boardHeight, neighbor, and a me tile (you can assume a user already entered these values, and you have access them as stored variables under these names). It will return either the string "True" or "False". For this function, imagine that the tile me is tile 3. Then all of its neighbors would be 2, 6, and 7. A neighbor is any tile on the board that touches (even in a single point) the tile me. A tile has at most eight neighbors. For example, a call to the function with verifyNeighbor(4,3,4,3) would return "False", because although 4 was a neighbor that could have been returned from the getNeighborLabels function, it is NOT a valid neighbor of 3 on this board.

Now you should be ready to write test cases for your code, once you understand what arguments each function is expecting (i.e. what the user would have supplied), and what it will return and when. For this project, we will expect your test cases to be written to a file called DriverJava.java (right mouse click and save the file). The example shows you the format for one test case of getNeighborLabels and one test case of verifyNeighbor. Each test case is two lines long: the first line contains a double quote, followed by the name of the function, followed by a space, followed by all of the arguments to the function, each separated by a single space, followed by a double quote, followed by a comma, and terminated by a newline. Then, on the next line, you should provide the expected answer for that function call, followed by a comma, and terminated by a newline. In your tests, make sure you include spaces where they need to be, otherwise they will not pass on Marmoset.

You should write at least forty two test cases for this project. Your test cases will be graded on Marmoset and are due a week before the project due date. To help you use your test cases, I have included a driver.py file that will use your DriverJava.java file and print out whether or not the tests you wrote passed or failed. To use this driver, make sure your project2.py, DriverJava.java, and driver.py are all in the same directory, and from a terminal in that directory, type:

python driver.py

The driver will print out all of the test cases passed and failed. (Remember they will all initially fail, before you have written any code, but this is fine, and you should still submit those test cases to Marmoset)

Once you have written your test cases (and submitted just the test cases to Marmoset), you can begin to write your code for the project in the file project2.py (and remember the link to the template for this file above).

Sample Input and Output

Your code will be tested on Marmoset in the same manner as your test cases. Two sample tests have been provided in the DriverJava.java above: these tests are the Public Tests on Marmoset.
Project Hints and Guidelines

Remember, when designing your own test cases, try to do so in a thoughtful and structured approach, as we have done in class. What is the smallest possible board you could call your functions on? What is the next smallest one? What are all the border cases?

You may find the and, or, is, is not, numeric comparison operators (<,>,<=,>=), and the abs(x) function useful for this project. You will also have to use if-else statements. You will need the return statement to get your functions to return a value.
Other hints and guidelines:
Project Grading

The project will be worth 100 points:

Project Submission

There are two due dates for the two different parts of the project (test cases and code). Once a due date passes you cannot resubmit that part of the assignment. However, you may submit either or part of both assignments before the first due date, if you are done early.

DUE DATE 1: Friday 6/13/2014 at 4:55pm: Test cases due. Submit ONLY your DriverJava.java file on Marmoset following the link to CS112-2T. (The T stands for TEST)

DUE DATE 2: Friday 6/20/2014 at 4:55pm: Code is due. In order to have your code work with Marmoset, you must also submit two files code.py and SystemCall.java. Again, you do not need to know how these files work (or even open them); just make sure not to change them, and submit them with your project2.py. Normally, Marmoset is set up to work with Java files, which is why we have this workaround. Submit ONLY your project2.py, code.py and SystemCall.java files on Marmoset following the link to CS112-2C. (the C stands for CODE). Find the link on Marmoset to submit Project 2. Once you pass all the public tests, use your tokens wisely to start examining the release tests. Do not change the name of the files.

You may make as many submissions to Marmoset as you like, before the due date, but we will only grade the highest score. Remember to read and adhere to all of the information regarding projects and their submission and grading on the course syllabus.
Allowable resources: Required class textbook, Professor and GTA, the Internet for looking up syntax errors and crashes only (for meaning). You may not look at or share other students' code in any manner. You may not look at or share test cases with other students. You may NOT work together or talk to other people (including outside sources besides the professor and GTA/UTAs) about the project. All work must be your own.