We all love the classic game of Checkers. In this project, we add a twist by introducing two new pieces: Bomb Pieces and Shield Pieces. For details on how these pieces differ from normal pieces, see Rules of Checkers61bl. You will be implementing your own GUI-supported version of this game. You should use the provided StdDrawPlus library to implement the GUI.
Warning: This project is time consuming and significantly more challenging than anything that you have seen so far in this course. It is also an individual project. Do not share code with other students. You can find the (bare-bone) starter code here.
2. Rules of Checkers61bl
Both players start with the same setup as checkers, as shown in this image:
The board is an 8x8 board, with water and fire pieces on the top and bottom. Each player starts with pieces in the three rows closest to them. The front, middle-most row consists of Bomb Pieces, the second row consists of Shield Pieces, and the back, edge-most row consists of normal pieces. Only every other space on the Board is used, and all pieces can only move and capture diagonally. If a capture move is available, the player is not required to capture. The bottom left corner should have a "black" square, and should contain a normal fire piece.
Movement of pieces are the same as classic Checkers, pieces can only move one square diagonally. In all new games, fire team makes the first move. Besides king pieces, fire pieces always move upwards (like flames) and water pieces always move downwards (like rain). Upon reaching the topmost row, fire pieces become "kinged" and are allowed to move not only diagonally forwards, but also diagonally backwards. The same can be said for water pieces that reach the bottommost row. Capturing a piece works exactly the same as in classic Checkers, by jumping over an opponent's piece. You may perform multi-captures like in classic Checkers.
Moves diagonally, and captures diagonally. Normal pieces can multi-capture, meaning if performing a capture lands the piece in a position ready to perform another capture, that piece may choose to do perform another capture in the same turn.
A normal Checkers piece with a twist. Performing a capture with a bomb piece causes an explosion in the destination landing. Explosions kill all pieces adjacent to the landing (pieces within a 3x3 block centered at the bomb's final position), as well as the exploding bomb. Howevever shield pieces will not be killed by a bomb explosion. Bombs do not discriminate; all non-shield pieces in the blast zone, regardless of if they are water or fire, are killed in a bomb explosion.
Chain reaction explosions do not occur. If one bomb destroys another bomb via explosion, a second explosion does not occur. Bomb pieces cannot perform multi-captures, because they explode after the first capture.
A normal checkers piece, except that it cannot be killed by bomb explosions. However, they can still be normally captured by any piece (including bombs).
The three images below is an example of an explosion example. Suppose that the blue player is Ross, and the red player is Armani. In the first image, Ross ponders his move. In the second image, Ross has selected the blue piece (highlighted). He’s about to perform a capture. In the third image, Ross’s water bomb piece has captured a fire bomb by moving diagonally down to the right and caused an explosion that effectively killed two additional fire bombs. Notice that Armani's fire shield has survived the explosion. Also notice how there is no chain reaction. Just because a bomb has been destroyed in an explosion does not mean it goes off and causes its own explosion. It is now Armani's turn (after spacebar is pressed).
Any piece can become "Kinged" upon reaching the furthest row from its origin side. King pieces can move and capture in four directions instead of only two. A piece may capture, promote to a king, and capture again in the same turn if the orientation of the Board permits.
3. The GUI
This spec will begin by explaining how the system should work as a whole. When it comes to implementation, you should consult the recommended order (below). While this section makes for nice narration, it's not the order in which you should work.
You will be provided StdDrawPlus.java, with all the methods you’ll need for creating a functional GUI. Do not modify any methods in StdDrawPlus.java. In your Board class, the main method starts a new game of Checkers61bl in GUI mode and doesn’t return until the game is over. For optimal visual appeal, we recommend having red/gray (instead of red/black) squares, though you're welcome to use whatever colors you'd like. In fact, you may even use your own pictures if you so wish. The GUI coordinate system should work as follows: A piece on (0,0) lies on the bottom left corner. A piece on (7, 7) lies on the top right corner. A piece on (0,7) lies on the top left corner. A piece on (7,0) lies on the bottom right corner.
When a user clicks on a square:
- You should first extract the coordinates of the piece.
- Then check if you can select a piece. (See canSelect in API.)
- If you are allowed to select the piece you clicked on, call select on its coordinates.
When a user presses spacebar:
- You should check if the current player is allowed to end their turn. (See endTurn in API)
- If so, you should make any changes necessary in ending the turn (i.e. switching players).
StdDraw is an library that was orginally from Princeton. We have slightly altered it for the purposes of this project, resulting in StdDrawPlus. The StdDrawPlus library is full of methods that will aid you in creating your GUI. Here are some methods you will find probably useful. These are static methods and thus to call them should be preceded by "StdDrawPlus". See DemoBoard.java for a more concrete example on how to use this library.
void setScale(int min, int max): Sets the scale for the GUI. You will most likely be setting the scale from 0 to 8.
boolean mousePressed(): Returns whether or not the mouse is pressed. A quick way to handle clicks is to set the time poll rate in StdDrawPlus.show to be reasonably quick (10-25 ms is a good ballpark).
double mouseX(), mouseY(): Returns the current xy coordinate of the mouse. If you click on a Piece at (x, y), you can get x and y by type-casting to an int.
isSpacePressed(): Returns whether spacebar is currently being pressed.
show(int time): Displays the current GUI for
timemilliseconds before continuing the program.
setPenColor(Color color): Changes the color of the pen. You should use one of the predefined colors in StdDrawPlus. They are static, you can call it by using StdDrawPlus.COLOR, replacing COLOR with the color you want.
filledSquare(int x, int y, int r): x, y are the center, r is the half-length of a side. Uses pen’s current color.
picture(int x, int y, String imgPath, int w, int h): places a picture located at imgPath centered at x, y are the center. An example of imgPath is "img/bomb-fire-crowned.png". You'll probably want to set w and h to 1 to fit one of the 64 squares. Generally, centering something on square (2,3) will require x to be 2.5 and y to be 3.5 (and so forth).
4. Required Methods / API
There methods/files are provided in the skeleton code and must be implemented. In addition to these methods, you are strongly encouraged to create additional variables and helper methods as necessary. Methods can be public, though try your best to make as many private as possible. Variables should not be public.
public static void main (String args)- starts a GUI supported version of the game.
public Board(boolean shouldBeEmpty)- The constructor for Board. If
shouldBeEmptyis true, initializes an empty Board. Otherwise, initializes a Board with the default configuration. Note that an empty Board could possibly be useful for testing purposes.
public Piece pieceAt(int x, int y)- Gets the piece at position (x, y) on the board, or null if there is no piece. If (x, y) are out of bounds, returns null.
public void place(Piece p, int x, int y)- Places p at (x, y). If (x, y) is out of bounds or if p is null, does nothing. If another piece already exists at (x, y), p will replace that piece. (This method is potentially useful for creating specific test circumstances.)
public Piece remove(int x, int y)- Executes a remove. Returns the piece that was removed. If the input (x, y) is out of bounds, returns null and prints an appropriate message. If there is no piece at (x, y), returns null and prints an appropriate message.
public boolean canSelect(int x, int y)- Returns true if the square at (x, y) can be selected.
A square with a piece may be selected if it is the corresponding player’s turn and one of the following is true:
- The player has not selected a piece yet.
- The player has selected a piece, but did not move it.
An empty square may be selected if one of the following is true:
- During this turn, the player has selected a Piece which hasn’t moved yet and is selecting an empty spot which is a valid move for the previously selected Piece.
- During this turn, the player has selected a Piece, captured, and has selected another valid capture destination. When performing multi-captures, you should only select the active piece once; all other selections should be valid destination points.
public void select(int x, int y)- Selects the square at (x, y). This method assumes canSelect (x,y) returns true. In respect to the GUI, when you select a Piece, color the background of the selected square white on the GUI via the pen color function. For any piece to perform a capture, that piece must have been selected first. If you select a square with a piece, you are prepping that piece for movement. If you select an empty square (assuming canSelect returns true), you should move your most recently selected piece to that square.
public void move(int x1, int y1, int x2, int y2)Assumes Piece p's movement from (x1, y1) to (x2, y2) is valid. Moves the piece at (x1, y1), to (x2, y2) capturing any intermediate piece if applicable.
public boolean canEndTurn()- Returns whether or not the the current player can end their turn. To be able to end a turn, a piece must have moved or performed a capture.
public void endTurn()- Called at the end of each turn. Handles switching of players and anything else that should happen at the end of a turn.
public String winner()- Returns the winner of the game: "Fire", "Water", "Tie", or null. If only fire pieces remain on the board, fire wins. If only water pieces remain, water wins. If no pieces remain (consider an explosion capture), no one wins and it is a tie. If the game is still in progress (ie there are pieces from both sides still on the board) return null. Assume there is no stalemate situation in which the current player has pieces but cannot legally move any of them (In this event, just leave it at null). Determine the winner solely by the number of pieces belonging to each team.
public Piece(int side, Board b)- Constructor for a normal Piece. side is the side of the Piece, either 0 for fire or 1 for water. b represents the Board that the piece is on. The new piece should not be a king.
public int side()- Returns 0 if the piece is a fire piece, or 1 if the piece is a water piece.
public boolean isKing()- Returns whether or not the piece has been crowned.
public void startCapturing()- Called after a Piece has captured. Makes sure that the piece's hasCaptured() method returns true.
public boolean hasCaptured()- Returns whether or not this Piece has captured another piece this turn.
public void finishCapturing()- Called at the end of each turn on the Piece that moved. Makes sure the piece's hasCaptured() returns false.
public void explode(int x, int y)- Causes this Piece to explode if it is a BombPiece, else does nothing. Refer to Rules of Checkers61bl for what an explosion is.
public void getBlownUp(int x, int y)-Causes this Piece to blow up, removing it from the Board, unless it is a ShieldPiece.
public ShieldPiece(int side, Board b)- Constructor for a Shield Piece. side is the side of the Piece, either 0 for fire or 1 for water. b represents the Board that the piece is on. The new piece should not be a king.
public BombPiece(int side, Board b)- Constructor for a Bomb Piece. side is the side of the Piece, either 0 for fire or 1 for water. b represents the Board that the piece is on. The new piece should not be a king.
Start early! Don't underestimate the project. Playing checkers is easy. Making it is harder than it seems. Make your method calls consistent. Calling canSelect on the same piece multiple times in a row should return the same answer. Advice steps after #4 are likely to undergo modification.
Recommended order of tasks / Checkpoints:
Remember to look at the GUI tips if you find yourself stuck.
- Read the spec and understand the overall picture. Understand how inheritance works in this system. Go through the different Pieces and understand what makes each Piece special.
- Create Board.java so that when you type
java Board, it displays a blank 8x8 board. (You will be implementing parts of your board as you go along). See
DemoBoard.javafor inspiration. You do not need to cite this assistance in your source files.
- Modify Board so that it starts up with the correct initial configuration of the board (first image in this spec). We do not recommend JUnit tests for this task, since it is likely to be easier for you to visually verify the correctness compared to writing a test. You should only do testing when you think it will save you time.
- Work through the Board methods.
placeare probably a good place (ha ha) to start. For the more complicated methods, it is highly recommended that you test these using JUnit instead of using your GUI and clicking around like mad to test. This will make you become insane. Don't forget about the false option in the Board constructor. It may be particularly handy for testing.
- Handle canSelect and select. (First check if it's the right player's turn, then check other conditions. These methods can be harder than you expect) Remember to make the selected square white.
- Implement canEndTurn and endTurn methods.
- Handle piece movement, regular piece capturing, and finally figuring out explode() and getBlownUp().
- Polish up your JUnit tests to make sure you've handled edge cases.
Bonus for Bosses
- Start a new game by pressing "n" in GUI mode. (Use the StdDrawPlus.isNPressed() method).
- Implement an undo method, reverting the board to the previous state.
- Make some cool animations and sounds to accompany bomb explosions on the gui. StdDrawPlus currently doesn't support animations/sounds, so you should Google for another library that can help you out.
- Handle the stalemate situation. Have the game terminate however you like when the current player has pieces, but cannot move any of them.
Project 1 is due Tuesday, July 7th at 11:59:59pm. Submit Board.java, Piece.java, BombPiece.java, and ShieldPiece.java as proj1.