General Description
|
The goal of this assignment is to implement an interactive two-player computer game. In this game two players take turns removing coins from two distinct piles (rows). The player who makes the last move, i.e. clears the game board by removing the last coin(s), is considered the winner.
The focus of this assignment is on expressing repetition (while loops), decisions (if-statements), and complex conditions (&&,||).
|
Here are the rules of the game:
- the game board consists of two rows of coins (referred to here as top row and bottom row)
- each row starts with a random number of coins chosen in a given range (the app will use the range
[10,20], so it is ok to use these fixed numbers where appropriate)
- on each move the player must remove at least 1 coin but no more than 5 coins per row
- the player has the option of removing coins from the top row only, from the bottom row only, or from both rows
- if the player chooses the option of removing coins from both rows, then the chosen number of coins is removed from both rows
- we will use integers to represent the rows: 1 for top row, 2 for bottom row and 3 for both rows and these numbers can be used directly where appropriate
- a player is not allowed to try to remove more coins than are available on the particular row(s)
- the winner is the player whose last move leaves the board empty
Throughout the game display messages to the players centered on the screen a quarter away from the top edge.
Preliminaries (New DrJava)
Download the new version of DrJava:
- right-click __drjava.jar__ and choose "Save As.."
- copy over "cs111/software.tmp/drjava/drjava.jar"
- check the toolbar for the new DrJava:
This DrJava version includes:
- logging functionality: the log should be submitted as part of the assignment
- paste restriction: pasting is disabled, except inside
run(); do not paste elsewhere even if the paste restriction happens to fail
- canvas functionality for touch and keyboard input
Preliminaries
Start DrJava and create a new project named
CoinsGameApp in folder
cs111/hw . See the Readings List notes on how to create a new project.
For this app the phone should be put in
landscape/tablet orientation.
App Stages
Make sure to test each procedure carefully before moving on to the next one.
The assignment is structured as a sequence of stages starting with a simple version of the app and adding smaller components each time. Your submission should only include the final version (last stage).
Handling invalid moves, interacting with two players, and getting input by touching the circles will be added gradually in different stages.
Color choices are up to you, but the messages for one of the players should be in one color and for the other player in a different color.
Stage 1
For this stage assume that:
- there is only one player (game still terminates when board is cleared)
- the player does not make invalid moves
- all necessary input is obtained via:
canvas.readInt( <short-message> )
Create the following procedures:
drawCirclesRow(startX, startY, radius, n)
This procedure draws a row of n touching circles each of the given radius such that the left-most circle is centered at (startX,startY). At the center of each circle draw its corresponding index, i.e. 1,2,3,... .
Note that canvas.drawText(...) can display any message type, i.e. the message can be a piece of text, an integer Post-It, or a real number Post-It, etc. (If you are unsure how to display the coin index, ignore it and come back to it later.)
|
drawCirclesRow(20, 80, 20, 5);
drawCirclesRow(50, 200, 15, 8);
|
drawGameBoard(topCoins, botCoins, radius)
This procedure draws two horizontal rows of touching circles of the same (given) radius. The top row has topCoins number of circles and the bottom row has botCoins number of circles.
- the top row of coins sits on the horizontal line that goes through the middle of the screen; the bottom row of coins is immediately below
- the left-most coin of each row is placed such that it touches the left border of canvas
This is a short procedure, no loops necessary. Just compute the starting coordinates for the two rows based on the diagram/description.
|
drawGameBoard(10, 12, 9.2);
drawGameBoard(9, 4, 15.5);
|
playGame()
This procedure will drive the game by displaying the board, waiting for the player's move, etc., and displaying a congratulatory message centered on the canvas.
Note: To show a keyboard in which the player types a number use:
canvas.readInt( <short message> )
Below is an outline in English for this procedure. It assumes that:
- there is only one player (no need to write any text messages)
- the player only makes legal moves
- the move choices are made via
canvas.readInt(<short-message>)
- at first assume that the player always removes coins from top row (i.e. player always types 1); the goal is to see the top row losing coins on each move
- next incorporate bottom row (i.e. player types 1 or 2); the goal is to see one or the other row losing coins on each move
- finally, incorporate both rows (i.e. player types 1 or 2 or 3); the goal is to see both rows losing coins when 3 is typed
Here is the procedure outline:
void playGame()
{
Set up Post-Its that keep track of the number of coins on each row
* for Stage 1 start each row with exactly 10 coins -- will randomize later
* these Post-Its should decrease throughout the game based on player choices
Compute the coin radius
* for Stage 1 just use 36 for coin radius -- will fix later.
Start the loop:
clear canvas, draw board
for now pause briefly to see board; remove later
ask player which row to remove from (type 1, 2, or 3 only)
ask player how many coins to remove
update coins on one (or both) rows based on the (row, coin) selection
* at first assume player only picks from top row and see if the board updates correctly
* for now do nothing when wrong number of coins picked; assume correct play
Anything else that needs to be done
}
|
|
Stage 2
This stage will make it a two-player game. This is a simple extension of Stage 1.
Add a Post-It to keep track of current player. This Post-It will alternate between two possible values (for example, 1, 2, 1, 2, 1, 2, ... or +1, -1, +1, -1, +1, -1).
Make any other relevant changes to display a message on the phone (either "BLUE Player's move" in bluish color or "RED Player's move" in reddish color), so that the players know whose turn it is.
The message should be centered horizontally and be down from the top edged a quarter of the height.
Since now there are two players, at the end of the game there should be a message that indicates who won.
Stage 3
This stage will make the game more realistic by selecting a random number of coins for each of the rows.
So far the number of coins has been fixed to 10 per row and the coin radius has been fixed to 36.
Update the app so that each row (independently) starts with a random number of coins chosen from
[10,20].
Note: You can get a random integer in the range
[low,high] from the canvas (write it down on a Post-It):
canvas.getRandomInt( <low>, <high> )
Since the number of coins varies each time the game is run we need to fix the radius of the coins. So far the radius has been set to 36, but this will no longer work if there are too many coins.
Write the following procedure so that the radius of the coins is no longer set to 32.8 (see Stage 1), but is computed based on the initial number of coins as the game begins.
Now use the above procedure inside
playGame to set the correct coin radius.
Play the game again. Below are sample screenshots. You might see something different, since each time random number coins are picked.
Each time you start the game the goal is to see that the longer row extends all the way to the end (it is ok if the longer row has a small gap at the end).
Once computed, the radius does not change throughout the game.
|
playGame(); // happened to start with 11(top), 10(bottom) coins
// coins are bigger, since started with 11 max
playGame(); // happened to start with 12(top), 14(bottom) coins
// coins are smaller, since started with 14 max
|
Stage 4
This stage will improve the game interaction by allowing the player to select the coins to remove by touching the screen. For example:
- scenario: player tapped once on coin 3 on the top row
effect: 3 coins will be removed from the top row
- scenario: player tapped once on coin 4 on the bottom row
effect: 4 coins will be removed from the bottom row
- scenario: player tapped twice on coin 5 on either row
effect: will remove 5 coins from the top row and 5 coins from the bottom row
Remove the canvas.readInt(...) sections and replace them with code that handles touch input. See these notes for an example on how to use touch input with the canvas. It shows how to get the coordinates of the touch, the number of taps, and what object is selected:
touch input
Write the following procedure to which computes the intended row:
computeRow(touchY, numTaps)
This procedure determines which row is selected based on the y-coordinate of the player's touch on the screen and the number of taps. It returns one of the values 1, 2, or 3:
- returns 1 (for top row) when the player has tapped once anywhere in the top half of the screen
- returns 2 (for bottom row) when the player has tapped once anywhere in the bottom half of the screen
- returns 3 (for both rows) when the player has tapped twice (regardless of the given
y coordinate)
- [ there is no
waitForTouch here; the touch has occurred elsewhere and here we only process the information ]
Here is how to test this procedure in run(). Note that the answers will show up in DrJava's Console Window (long panel at the bottom), not on the phone:
public void run()
{
int row = computeRow( 123, 1 );
System.out.println( "selected row: " + row ); // should see 1: y=123 is in top half of phone and 1 tap
row = computeRow(123, 2);
System.out.println( "selected row: " + row ); // should see 3: y ignored, since 2 taps
// y below middle and 1 or 2 taps
row = computeRow(280, 1);
System.out.println("selected row = " + row); // should see 2: y=280 is in bottom half of phone and 1 tap
row = computeRow(280, 2);
System.out.println("selected row = " + row); // should see 3: y ignored, since 2 taps
}
Make sure you can play the game by tapping the coins on the screen.
Stage 5
This you will add error messages. If the latest move violates one of these rules an appropriate messages should be displayed (each case should have its own message):
- number of coins picked is larger than allowed in the game
- (single row) number of coins picked is larger than what is available on selected row
- (both rows) number of coins picked is larger than what is available on one of the rows
Draw the message and pause briefly (the
error message should be one eighth from the top edge of the screen, i.e. above the
player move message) . Nothing else needs to be done -- the player simply forfeits the turn (board should not change).
This is just an extension of the code that updates the coins on the board with a few additional
if-statements using
&& ||. Think about correct order/placement.
What to turn in
Turn in the Java code for the app in the
Assignment 4 dropbox:
- open Finder/FileExplorer and go to folder
cs111 (where you run DrJava)
- go to
hw/ConisGameApp/src/cs1/CoinsGameApp (this is where your code is saved)
- upload the files
CoinsGameApp.java and CoinsGameApp.log (ignore the other files)