Assignment 6: Third Time’s a Charm – Three Trios, part 2
1 Purpose
2 Preparation:   fixing up your models
2.1 Making your models read-only
2.2 Adding missing functionality
3 Visualizing the game
3.1 Required appearance
3.2 Required behavior
3.3 Running your view
3.4 Testing your view
4 Strategic computer players
4.1 Required behavior
4.2 Extra credit
4.3 Testing your strategies
4.3.1 Mocking your model
5 What to do
6 What to submit
7 Grading standards
8 Submission
8.9

Assignment 6: Third Time’s a Charm – Three Trios, part 2

Due dates:

Starter files: code.zip

1 Purpose

In this portion of the project, you will be building a visual view of your game, and also start building the computer strategies for playing the game. This assignment has several parts. Look over the outline on the left, and skim through the whole assignment, before diving deeply into any one section. The assignment lists requirements in the recommended order you should do them, but future tasks might give you ideas for how to improve earlier ones.

2 Preparation: fixing up your models

2.1 Making your models read-only

As we discussed in class, views should not have the ability to mutate the models they are viewing: this would bypass the controller, making it impossible to reliably control the model.

Refactor your model interface, if necessary, into two interfaces: your ThreeTriosModel interface (or whatever you named it) should now extend a ReadonlyThreeTriosModel interface (again, choose a name that matches your existing model). The read-only interface should contain all the observation methods of your model, while the mutable sub-interface should contain all the mutator methods.

2.2 Adding missing functionality

The following is a non-exhaustive checklist of functionality that is necessary for Three Trios to work properly. Your model interface(s) may not yet expose all of these as methods, or might not make it easy to use.

Reexamine the design and implementation of your model from the previous assignment, and improve it to include the functionality above. Document whatever changes you made in a new section of your README, entitled “Changes for part 2” — explain what functionality was missing, and why, and how you chose to add it.

(Note: the previous assignment did not define exactly what a player’s score should be, only how to determine the winner. We will explicitly state that a player’s score is simply the number of cards that player owns in their hand plus the number of cards that player owns on the grid.}

3 Visualizing the game

To implement your view, you will need to use Java Swing. (You are not permitted to use the javalib library we used in Fundies 2, as it conflates the notions of model, view and controller into a single World class. You are also not permitted to use JavaFX, as that has been deprecated and is overly complicated as well.) The code provided with the MVC code and the Turtles activity from class give you a basic beginning using Swing, as well as the exercises in Lab 8.

You have also been provided with an extensive list of different Swing layouts, components, and their uses in the code linked at the start of the assignment. If you need a more visual way of seeing Swing things done, here is a video covering a lot of basic Java Swing components and listeners. Note that if you try to write your code in the way shown in the video or in the way shown in the given code above, you will not do well on the assignment. The video does not follow our design rules nor separates code properly into the three components. The code given has no helpers at all nor follows any of our design considerations.

You will likely need to design at least one, and possibly three, interfaces for your view: one should describe what the frame ought to be capable of, and one for each panel might be needed to describe what the panel ought to be capable of. (These may be empty interfaces for now, if you do not see a need for any methods in them yet...but keep reading below for additional ideas.) Note that your textual rendering from the previous assignment does not have to implement this new GUI view interface, and you do not have to force it to do so.

3.1 Required appearance

Your view should look as much as possible like the screenshots shown in the previous assignment. Here is review of what the game can look like at the start.

Here is a view of the game mid-game:

You may decorate the image if you wish, or adjust the color palette, or even change the font, but it should still be recognizably like the above. That means a user can easily identify which hand belongs to which player, where the grid is, and on that grid which cells are holes and which are card cells.

Looking through the documentation of the Graphics2D class, you’ll find several useful methods for drawing text, lines, ovals, images, and shapes; and for transforming the coordinate system (scaling, translating and rotating) to affect where drawings are placed. We recommend building a subclass of Path2D.Double that represents “a card” of whatever size makes sense in your view. You can then draw multiple such cards wherever needed to make up your rendering: this will be much easier than attempting to draw all the individual edges of the cards separately.

The size of drawn strings is controlled by the size of the font used in the Graphics2D object. I suggest reading up on the Font class to find methods to help change the font size to whatever works best as you resize the window.

3.2 Required behavior

Your view should have a constructor that takes in a ReadonlyThreeTriosModel not the mutable interface! — to ensure that your view is incapable of modifying the model even accidentally.

In preparation for the next assignment (where you will build controllers), you should equip your view with the ability to handle mouse clicks. In particular,

Your view should let the user deselect a selected card in the hand by

Clicking outside the boundary of the grid or the hand must not cause your view to crash, throw an exception, or otherwise break.

You may want to revisit the discussion of Features interfaces from Lecture 13: GUI Basics, and this may influence your view interface designs. You should also consider which component should do the printing to System.out. This will also help you plan out your controller ahead of the next assignment.

Finally, we should be able to resize your window larger and smaller and all of the above functionality should still work correctly. Note you are not responsible for the visual attracting that can occur at extremely small sizes.

3.3 Running your view

Add the following placeholder class to your project:

package cs3500.threetrios;

public final class ThreeTrios {
  public static void main(String[] args) {
    YourModel model = ...create an example model...
    YourView view = new YourView(model);
    view.setVisible(true);
  }
}

As we’ve done several times, our main() method simply instantiates a model, instantiates a view using that model, and tells the view to get started. In later assignments we will augment this to create controllers, players, and make the game playable.

3.4 Testing your view

Testing views can be quite tricky, since you cannot simply use JUnit assertions to check them for “equality”. For this assignment, you do not need to unit-test your visual view, but you should include in your submission at least four screenshots of your view:

Name the screenshots appropriately, so you and graders can easily tell what they represent. Also, make sure the screenshots are reasonably sized. There is no reason to have a 4K png of your view.

4 Strategic computer players

Playing ThreeTrios for any amount of time quickly leads to noticing two aspects of the strategies required for key play: which card to choose and then where to place the card.

  1. Flip as many cards on this turn as possible. This means choosing a position and card together.

  2. Go for the corners: cards in corners only expose two of their attack values instead of all 4, making them harder to flip. Then consider which card is hardest to flip in that corner.

  3. Choose cards that are less likely to be flipped in general. That means considering for each position, for each card, for each direction, figuring out how many of the opponent’s cards can flip them. The card and position combination with the smallest chance of being flipped should be the play.

  4. A fancier approach might choose the move that leaves their opponent in a situation with no good moves. (This approach minimizes the maximum move the opponent can make, and is known as a minimax strategy.) To calculate the "best" move an opponent can make, you must make some guess as to what strategy that opponent is using...and it might be any of these strategies we’ve seen so far.

(There are far more sophisticated strategies than these, but these will do for now!)

4.1 Required behavior

Implement the first two of these strategies. If there are multiple "best" moves that can be chosen in a single strategy, break ties by choosing the move with the uppermost-leftmost coordinate for the position and then choose the best card for that position with an index closest to 0 in the hand . (Note: this is not a good real-life strategy! But it will make your testing substantially easier to have a deterministic way of breaking ties.) If there are no valid moves, your player should pass choose the upper-most, left-most open position and the card at index 0.

Hint: Keep in mind that a strategy needs to know which player it’s trying to pick a move for!

You must test these strategies, and in particular demonstrate that it resolves ties correctly.

Hint: You may have an easier time implementing your strategies if you generalize their signature somewhat: Unlike the Tic Tac Toe strategies, where moves didn’t have a numerical value, moves here do have a potential score. The possibility of ties implies that your strategy’s signature should return more than just a single move possibility...

4.2 Extra credit

As we discussed with Tic Tac Toe, you can chain these strategies to form strategies of varying sophistication. A simplistic strategy would just use option 1; a smarter strategy might stack on options 2 and 3, as well to further break ties in option 1. Some of these strategies may result in multiple, equally-good options: in case of such ties, again choose the move with the uppermost-leftmost coordinate.

Some of these strategies may result in no valid moves: you must figure out how to represent such situations and what they should (eventually) do in the model.

Your task to get extra credit:

In your README, explain what the extra credit strategies you implemented were and where we can find their implementations and tests. If your README does not state this, you will get no extra credit.

4.3 Testing your strategies

The elegant feature of strategies is that they are simply function objects, and so they are eminently testable. Build a collection of example games in known configurations, ask each strategy where it would choose to move for a given player, and check that the result is as expected.

If you’ve implemented multiple strategies, test them thoroughly: in particular, make sure you test scenarios that demonstrate the differences between them.

4.3.1 Mocking your model

One of the challenges of testing your strategies is that they depend on your model working correctly: the model needs to implement the complicated game logic of legality checking and scoring, and if those are buggy, your strategies may give unexpected results. But obviously, you can’t execute a strategy without some model object to examine!

In class we discussed mocks, that are stub implementations of interfaces that can give simulated answers and that can record a transcript of what methods were used. Here are two ideas for mocking your model; you should use these (and probably several more) to test your strategies:

5 What to do

  1. Refactor your model to split it into read-only and mutable interfaces.

  2. Design your view interfaces, and then begin implementing your views.

  3. Design your strategy interface(s) and implementation(s). Test them, using mocks of your models as necessary.

  4. Update your README file to include explanations of all the new classes you’ve designed. Be sure to include a “Changes for part 2” section documenting what you changed from your initial design.

6 What to submit

To create a JAR file, do the following:

7 Grading standards

For this assignment, you will be graded on

8 Submission

Please submit your homework to https://handins.ccs.neu.edu/ by the above deadline. Then be sure to complete your self evaluation by its due date.