Assignment 2: The Model
1 Purpose
2 The game of Marble Solitaire
2.1 Context
2.1.1 Game Play
3 Building Marble Solitaire
3.1 Expected operations
3.2 Examples
3.3 Your Implementation
3.4 Testing
4 Package Management
5 List of Deliverables
6 Grading Standards
7 Submission
7.4

Assignment 2: The Model

Due: Thurs 09/27 at 8:59pm; self-evaluation due Fri 09/28 at 9:59pm

Starter files: code.zip

Note: The description may make assignments seem longer than they are. Distilling the description to make a list of all the things you are actually supposed to do will go a long way in having a good plan to tackle it. Read the description several times to confirm this list before acting on it!

1 Purpose

The primary goal of this assignment is to practice implementing an interface based on given specifications, and by choosing an appropriate data representation that helps in providing the functionality promised by the interface.

Please ensure all of your source code is in the cs3500.marblesolitaire.model.hw02 package. (See Package Management below.)

2 The game of Marble Solitaire

2.1 Context

Image credit: Photo by Gnsin edited by WolfgangW. (Photo by Gnsin GFDL or CC-BY-SA-3.0, via Wikimedia Commons)

In the next three assignments, you will implement a game called “Peg Solitaire”. This is a board game played by a single player. The game involves moving pegs on a game board with holes. Many modern versions using marbles instead of pegs, giving it the name “Marble Solitaire”. The image above shows a Marble Solitaire board. It is referred to as a Solitaire-type game, and is also called Brainvita in some countries. If you have not played this game before, try it here!

2.1.1 Game Play

The game starts by arranging marbles on the board. Exactly one slot is empty, and is traditionally the center slot.

A move is made by making one marble jump over exactly one marble and land in an empty slot exactly two positions away. When such a move is made, the marble that is jumped over is removed. Therefore, each single valid move increases the number of empty slots by one. A marble can only jump orthogonally (i.e. horizontally or vertically). The game ends when no more valid moves can be made. At any point in the game, the score is the number of marbles on the board. The objective of the game is to make moves so as to end up with the minimum score when the game ends.

In this assignment you will write the model for this game. The model will maintain the state of the game and allow a client to specify moves. You are not required to make the game playable at this point.

3 Building Marble Solitaire

3.1 Expected operations

In order to play the game, the client would expect the following operations: start a new game, make a move, get the current state of the game, get the current score and know when the game has ended. These operations have been specified and documented in the provided MarbleSolitaireModel interface. You are not allowed to change the interface in any way!

A short explanation of the methods in the interface follows:

3.2 Examples

You must check that your MarbleSolitaireModelImpl implementation of the MarbleSolitaireModel interface works as specified. We recommend that you create an empty implementation, and then proceed to write your tests. This will allow you to understand how your class will be used, which will help you to implement it. Please review the testing recommendations. Since you are testing the public-facing behavior of this interface, following those guidelines means that you should not place this testing code in the cs3500.marblesolitaire.model.hw02 package, but rather place it in the default package.

3.3 Your Implementation

Implement the MarbleSolitaireModel interface in a class called MarbleSolitaireModelImpl:

  1. Design a suitable representation of this game. Think carefully about what fields and types you will need, and how possible values of the fields correspond to game states.

  2. Although the traditional game is as shown above, we can generalize the dimensions of this board while retaining its shape. We define the arm thickness as the number of marbles in the top row (or bottom row, or left or right columns). In the traditional game, the arm thickness is 3, making the length of the largest row/column 7. In general, a board of arm thickness a is a board with a single square of size a, with 4 squares of the same size joined at its four sides to form a plus shape. In order to keep the “center” unique, the arm thickness must be an odd number to be valid. The board scales while keeping the four arms of the plus shape the same size.

  3. Positioning: A position is specified using a pair (row, column), assuming that the board is laid on a rectangular grid. The row and column numbers start at 0 in the top-left corner, increasing top to bottom and left to right respectively. For example in the above picture, the positions of the three marbles in the top row are (0, 2), (0,3) and (0, 4) respectively. The empty slot is at (3, 3).

  4. Instantiating the game: Your class should support four ways to instantiate it:

    • The first constructor should take no parameters, and initialize the game board as shown above (arm thickness 3 with the empty slot at the center).

    • A second constructor should take two parameters: sRow and sCol. It should initialize the game board so that the arm thickness is 3 and the empty slot is at the position (sRow, sCol). If this specified position is invalid, it should throw an IllegalArgumentException with a message "Invalid empty cell position (r,c)" with r and c replaced with the row and column passed to it.

    • The third constructor should take the arm thickness as its only parameter and initialize a game board with the empty slot at the center. It should throw an IllegalArgumentException if the arm thickness is not a positive odd number.

    • Finally a fourth constructor should take the arm thickness, row and column of the empty slot in that order. It should throw an IllegalArgumentException if the arm thickness is not a positive odd number, or the empty cell position is invalid.

    Carefully think about the shape of the board and our positioning scheme to infer which positions are invalid.

  5. The game state: The getGameState method may be used to print the game state in the format illustrated below. Specifically each slot should be one character (' ', 'O' or '_') and there should be one space between the positions. There should be no spaces after the last slot in a row. The following shows the output corresponding to the screenshot above:

        O O O
        O O O
    O O O O O O O
    O O O _ O O O
    O O O O O O O
        O O O
        O O O

    NOTE: The string you return should not have a newline at the end of the last line.

  6. Move: The move method should make the move and change the game state appropriately. A move is valid if all these conditions are true: (a) the “from” and “to” positions are valid (b) there is a marble at the specified “from” position (c) the “to” position is empty (d) the “to” and “from” positions are exactly two positions away (horizontally or vertically) (e) there is a marble in the slot between the “to” and “from” positions. Any invalid move should result in an IllegalArgumentException exception with an appropriate message on a single line. The text of the message is up to you.

    For example, the only valid moves on the board shown above start from (5, 3), (1, 3), (3, 1) or (3, 5), and all move to (3, 3).

Be sure to properly document your code with Javadoc as appropriate. Method implementations that inherit Javadoc need not provide their own unless they implement something different or in addition to what is specified in the inherited documentation.

File Hw02TypeChecks.java contains a small class designed to help you detect when your code may not compile against the grading tests. In particular, if your project cannot compile while Hw02TypeChecks.javaunmodified!—is a part of it, then it won’t compile for the course staff either.

3.4 Testing

Read the testing recommendations again.

4 Package Management

To make sure that your packages are in the correct layout, you should tell IntelliJ to do the following. Do this early, before you’ve written much code, to ensure that your files wind up in the right locations automatically, instead of having to fix it afterward:

5 List of Deliverables

Again, please ensure all of your project’s source is in the cs3500.marblesolitaire.model.hw02 package. The autograder will give you an automatic 0 if it cannot compile your code! Place your tests in the default package.

6 Grading Standards

For this assignment, you will be graded on

7 Submission

Wait! Please read the assignment again and verify that you have not forgotten anything!

Please compress the src/ and test/ folders into a zip file and submit it. After submission, check your submitted code to ensure that you see two top-level folders: src/ and test/. If you see anything else, you did not create the zip file correctly!

Please submit your assignment to https://handins.ccs.neu.edu/ by the above deadline. Then be sure to complete your self evaluation by the second deadline.