Need a solution. Overview We\'re moving back in time, from the 1990\'s and Tetri
ID: 3731499 • Letter: N
Question
Need a solution.
Overview
We're moving back in time, from the 1990's and Tetris, to the 1890's and the game of Dots and Boxes (Links to an external site.)Links to an external site.. This still-popular pencil-and-paper game can be found everywhere, from paper placemats and kids' menus in restaurants, to dozens of variants available for mobile and online play.
Objectives
Once again you must develop an implementation of an interface. Your implementation will need to keep track of all aspects of this game. There is no user interface, as we are building the underlying game engine. As in other projects, you'll be provided a few additional classes to assist with your implementation. The focus here is on somewhat advanced uses of collections, as well as on exception management. You have a lot of freedom here to design and develop your code in any way you see fit, so your guidance will be somewhat more limited than in the past projects.
Requirements
The interface is called edu.vt.cs5044.DotsAndBoxes and your implementation must be called edu.vt.cs5044.DABGame. You must of course create a test class as well, called edu.vt.cs5044.DABGameTest and achieve full code coverage. You are expected (and required) develop at least one additional helper class in the same package, with any reasonable name, in order to reduce the overall complexity of your implementation.
Downloads
dab5044.jar - library file containing the compiled utility classes and interface
dab5044-api.jar - library file containing the Javadocs for the utility classes and interface
Getting Started
Start a new project in Eclipse, then import the files above exactly as you did with the files for the Tetris project. You'll need to use a lot of what you learned in that assignment to complete this assignment. Be sure to thoroughly review the API details for all the provided classes. Everything you need to know is in the API. There is no user interface of any kind, nor any other way to run your implementation beyond your own test class, so a test-driven development strategy will be important to follow.
Explanation / Answer
DABGameTest.java
package edu.vt.cs5044;
import static org.junit.Assert.*;
import java.util.TreeMap;
import org.junit.Before;
import org.junit.Test;
@SuppressWarnings("javadoc")
public class DABGameTest
{
// Initialize local DABGame variable
private DotsAndBoxes game;
// Initialize and declare local variable for coordinates
private Coordinate coord1 = new Coordinate(0, 0);
private Coordinate coord2 = new Coordinate(1, 0);
private Coordinate coord3 = new Coordinate(0, 1);
private Coordinate coord4 = new Coordinate(1, 1);
// Initialize and declare local variable for default direction
private Direction dir = Direction.EAST;
// Create new DABGame
@Before
public void setUp()
throws Exception
{
game = new DABGame();
}
/*
* Ensure game exception is thrown if a new grid has not been initialized for every method
*/
@Test
public void testPreInit()
{
try
{
game.drawEdge(coord1, dir);
fail("drawEdge needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
try
{
game.getCurrentPlayer();
fail("getCurrentPlayer needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
try
{
game.getDrawnEdgesAt(coord1);
fail("getDrawnEdgesAt needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
try
{
game.getOwnerAt(coord1);
fail("getOwnerAt needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
try
{
game.getScores();
fail("getScores needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
try
{
game.getSize();
fail("getSize needs a Game Exception");
}
catch (GameException ge)
{
// PASS
}
}
/*
* Test init method to ensure GameException is thrown if parameter is less than 2
*/
@Test(expected = GameException.class)
public void testInvalidInit()
{
game.init(1);
}
/*
* Test getSize method after a grid has been initialized
*/
@Test
public void testGetSizeAfterInit()
{
game.init(2); // SETUP
assertTrue(game.getSize() == 2);
}
/*
* Test getCurrentPlayer method after a grid has been initialized
*/
@Test
public void testGetCurrentPlayerAfterInit()
{
testGetSizeAfterInit(); // SETUP
assertEquals(Player.ONE, game.getCurrentPlayer());
}
/*
* Test drawEdge method after grid has been initialized
*/
@Test
public void testDrawEdgeAfterInit()
{
testGetSizeAfterInit(); // SETUP
assertTrue(game.drawEdge(coord1, dir));
}
/*
* Test getDrawnEdges method on box
*/
@Test
public void testGetDrawnEdgesOnBoxThatContainsEdge()
{
testDrawEdgeAfterInit(); // SETUP
assertTrue(game.getDrawnEdgesAt(coord1).contains(Direction.EAST));
}
/*
* Test drawEdge method on a box that already contains the edge
*/
@Test
public void testDrawEdgeOnBoxThatContainsEdge()
{
testDrawEdgeAfterInit(); // SETUP
assertFalse(game.drawEdge(coord1, dir));
}
/*
* Test getOwnerAt method after grid has been initialized
*/
@Test
public void testGetOwnerAtAfterInit()
{
testGetSizeAfterInit(); // SETUP
assertTrue(game.getOwnerAt(coord1) == null);
}
/*
* Test directionNotNull to ensure if null parameter is entered for direction a GameException
* is thrown
*/
@Test
public void testDirectionNotNullWithNullDirection()
{
Direction nullDir = null;
testGetSizeAfterInit(); // SETUP
try
{
game.drawEdge(coord1, nullDir);
fail();
}
catch (GameException ge)
{
// PASS
}
}
/*
* Test the getOwner method after a box has been owned
*/
@Test
public void testGetOwnerAfterBoxIsOwned()
{
testGetSizeAfterInit(); // SETUP
game.drawEdge(coord1, Direction.EAST); // P1
game.drawEdge(coord1, Direction.SOUTH); // P2
game.drawEdge(coord1, Direction.WEST); // P1
game.drawEdge(coord1, Direction.NORTH); // P2
assertEquals(Player.TWO, game.getOwnerAt(coord1));
}
/*
* Test getScores method after a box is owned for player 2
*/
@Test
public void testGetScoresAfterABoxIsOwnedP2()
{
testGetOwnerAfterBoxIsOwned(); // SETUP
TreeMap<Player, Integer> scores = (TreeMap<Player, Integer>)game.getScores(); // Local var
assertTrue(scores.get(Player.TWO) == 1);
}
/*
* Test getScores method after a box is owned for player 1
*/
@Test
public void testGetScoresAfterABoxIsOwnerP1()
{
testGetSizeAfterInit();
game.drawEdge(coord1, Direction.NORTH);
game.drawEdge(coord1, Direction.EAST);
game.drawEdge(coord1, Direction.SOUTH);
game.drawEdge(coord4, Direction.SOUTH);
game.drawEdge(coord1, Direction.WEST);
TreeMap<Player, Integer> scores = (TreeMap<Player, Integer>)game.getScores();
assertTrue(scores.get(Player.ONE) == 1);
}
/*
* Test if player is null after a game is completed
*/
@Test
public void testPlayerNullAfterGameOver()
{
testGetSizeAfterInit(); // SETUP
game.drawEdge(coord1, Direction.EAST); // P1
game.drawEdge(coord1, Direction.SOUTH); // P2
game.drawEdge(coord1, Direction.WEST); // P1
game.drawEdge(coord1, Direction.NORTH); // P2
game.drawEdge(coord2, Direction.EAST); // P2
game.drawEdge(coord2, Direction.SOUTH); // P2
game.drawEdge(coord2, Direction.WEST); // P1
game.drawEdge(coord2, Direction.NORTH); // P2
game.drawEdge(coord3, Direction.EAST); // P1
game.drawEdge(coord3, Direction.SOUTH); // P2
game.drawEdge(coord3, Direction.WEST); // P1
game.drawEdge(coord3, Direction.NORTH); // P2
game.drawEdge(coord4, Direction.EAST); // P1
game.drawEdge(coord4, Direction.SOUTH); // P2
game.drawEdge(coord4, Direction.WEST); // P1
game.drawEdge(coord4, Direction.NORTH); // P2
assertTrue(game.getCurrentPlayer() == null);
}
/*
* Test drawEdge method that completess an adjacent box
*/
@Test
public void testDrawEdgeThatCompletesAdjBox()
{
testGetSizeAfterInit(); // SETUP
game.drawEdge(coord1, Direction.SOUTH); // P1
game.drawEdge(coord1, Direction.WEST); // P2
game.drawEdge(coord1, Direction.NORTH); // P1
game.drawEdge(coord2, Direction.WEST); // P2
assertEquals(Player.TWO, game.getOwnerAt(coord1));
}
/*
* Test that a game exception is thrown if there is no adjacent box for a given edge of a box
*/
@Test
public void testGameExceptionAdjNotValid()
{
try
{
game.drawEdge(coord1, Direction.NORTH);
fail("Must throw game exception");
}
catch (GameException ge)
{
// PASS
}
}
}
DABGame.java
package edu.vt.cs5044;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
public class DABGame
implements DotsAndBoxes
{
private Player currentPlayer;
private int gridSize;
private HashMap<Coordinate, Box> boxGrid;
@Override
public boolean drawEdge(Coordinate coord, Direction dir)
{
// Local boolean variables used to determine if player has additional move(s)
boolean boxOwned = false;
boolean adjOwned = false;
// Local box variable representing the box at coord parameter
Box selectedBox = findBox(coord);
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Determine if dir parameter is null, if it is game exception is thrown
checkDirectionNotNull(dir);
// If box selected at coordinates already has dir edge drawn, drawEdge method returns false
if (selectedBox.hasEdge(dir))
{
return false;
}
// If box selected does not have dir edge already drawn then draw edge
selectedBox.drawEdge(dir, currentPlayer);
// If the box has been completed it will have an owner equivalent to the current player, and
// the boxOwnded local boolean variable will be set to true
boxOwned = checkBoxOwner(selectedBox);
try
{
// Find the adjacent box and set it to local variable, if it exists. If not game
// exception is thrown
Box adjacentBox = findBox(coord.getNeighbor(dir));
//Declare and initialize new direction variable for opposite direction
Direction adjDir = dir.getOpposite();
// Draw the edge on the adjacent box
adjacentBox.drawEdge(adjDir, currentPlayer);
// If the box has been completed it will have an owner equivalent to the current player,
// and the boxOwnded local boolean variable will be set to true
adjOwned = checkBoxOwner(adjacentBox);
}
// Catch game exception to be handled if thrown
catch (GameException ge)
{
//Game exception caught
}
// If the boxOwned boolean variable has not been set to true it indicates that no boxes
// have been completed and it is the opponents turn
if (!boxOwned && !adjOwned)
{
currentPlayer = currentPlayer.getOpponent();
}
// Determine if game is over
checkGameOver();
// Return true if the method has been successfully completed
return true;
}
/**
* {@inheritDoc}
*/
@Override
public Player getCurrentPlayer()
{
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Return the value of the currentPlayer field
return currentPlayer;
}
/**
* {@inheritDoc}
*/
@Override
public HashSet<Direction> getDrawnEdgesAt(Coordinate coord)
{
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Select the box at the given coord, if the coord aren't on the board a game exception is
// thrown
Box selectedBox = findBox(coord);
// Return a HashSet of the edges already drawn for a box at given coordinates
return selectedBox.getDrawnEdges();
}
/**
* {@inheritDoc}
*/
@Override
public Player getOwnerAt(Coordinate coord)
{
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Select the box at the given coord, if the coord aren't on the board a game exception is
// thrown
Box selectedBox = findBox(coord);
// Return the owner of the selected box. Value will be if no player owns box
return selectedBox.getOwner();
}
/**
* {@inheritDoc}
*/
@Override
public TreeMap<Player, Integer> getScores()
{
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Instantiate a new TreeMap
TreeMap<Player, Integer> scores = new TreeMap<>();
// Local variables to hold the score of either player while method iterates through grid
int playerOneScore = 0;
int playerTwoScore = 0;
// Iterate through grid and count the number of boxes owned by either player
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
Coordinate currentCoord = new Coordinate(x, y);
Box currentBox = findBox(currentCoord);
Player boxOwner = currentBox.getOwner();
if (Player.ONE.equals(boxOwner))
{
playerOneScore++;
}
if (Player.TWO.equals(boxOwner))
{
playerTwoScore++;
}
}
}
// Add key value pairs for player and their score to the scores TreeMap
scores.put(Player.ONE, playerOneScore);
scores.put(Player.TWO, playerTwoScore);
// Return the scores TreeMap
return scores;
}
/**
* {@inheritDoc}
*/
@Override
public int getSize()
{
// Determine if a grid has been initialized, if not game exception is thrown
checkInit();
// Return the integer value of the gridSize field
return gridSize;
}
/**
* {@inheritDoc}
*/
@Override
public void init(int size)
{
// If the size parameter is less than 2 throw a game exception
if (size < 2)
{
throw new GameException("Grid size must be at least two.");
}
// Set the gridSize field to the value of the size parameter
gridSize = size;
// Set currentPlayer field to Player.ONE
currentPlayer = Player.ONE;
// Create TreeMap for boxGrid with (coordinates, boxes) as key value pair
boxGrid = new HashMap<>();
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
boxGrid.put(new Coordinate(x, y), new Box());
}
}
}
/**
* Create a new DABGame object.
*/
public DABGame()
{
currentPlayer = null;
gridSize = -1;
}
/**
* Helper method to determine if new game has been initialized
*/
private void checkInit()
{
// If the gridSize still equals -1 it indicates a grid has not yet been initialized and
// throws a game exception
if (gridSize == -1)
{
throw new GameException("Can't get size; not initialized");
}
}
/**
* Helper method to find a specific box when given a coordinates, if the given coordinates are
* outside the bounds of the game, a game exception will be thrown.
*
* @param coord
* is the coordinate where the box is located
*/
private Box findBox(Coordinate coord)
{
// The x and y values of the coordinate parameter
int xVal = coord.getX();
int yVal = coord.getY();
// If one or more of the values of the coordinates do not exist on the grid, throw a new
// game exception
if (xVal < 0 || yVal < 0 || xVal >= gridSize || yVal >= gridSize)
{
throw new GameException("That box doesn't exist; please select different coordinates.");
}
// If coordinates are valid, return the box object at the coordinates
Box selectedBox = boxGrid.get(coord);
return selectedBox;
}
/**
* Helper method to determine if direction is not null. Will throw a game exception if player
* attempts to give "null" direction
*
* @param dir
* the direction to be tested
*/
private void checkDirectionNotNull(Direction dir)
{
// If direction is null throw a new game exception
if (dir == null)
{
throw new GameException("Can't use direction null; please select another direction.");
}
}
/**
* Helper method to determine if a box has all four edges drawn
*/
private boolean checkBoxOwner(Box currentBox)
{
// If the current box owner is null return false; otherwise return true
return currentBox.getOwner() != null;
}
/**
* Helper method to determine if game is over
*/
private void checkGameOver()
{
// Local variable that will hold the value of player one and player two scores combined
int currentScoresTotal = 0;
// Local integer variable that is the total boxes available to be owned on a given grid
int totalAvailableBoxes = (int)Math.pow(gridSize, 2);
// TreeMap of the players current scores
TreeMap<Player, Integer> scores = getScores();
// Create key set for scores map
Set<Player> keys = scores.keySet();
// Iterate through keyset and add the key values to the currentScoresTotal variable
for (Player key : keys)
{
currentScoresTotal += scores.get(key);
}
// If currentScoresTotal is equal to the totalAvailableBoxes variable it indicates that all
// boxes have been drawn and the game is over. CurrentPlayer will be set to null.
if (currentScoresTotal == totalAvailableBoxes)
{
currentPlayer = null;
}
}
}
Box.java
import java.util.HashSet;
public class Box
{
private Player owner;
private HashSet<Direction> drawnEdges = new HashSet<>();
/**
* Get the current value of owner.
*
* @return The value of owner for this object.
*/
public Player getOwner()
{
return owner;
}
/**
* Get the current value of drawnEdges.
*
* @return The value of drawnEdges for this object.
*/
public HashSet<Direction> getDrawnEdges()
{
HashSet<Direction> copyOfDrawnEdges = new HashSet<>(drawnEdges);
return copyOfDrawnEdges;
}
/**
* Determine whether the drawnEdges collection of a box contains a direction
*
* @param dir
* the direction the method will test to determine if it already exists in the
* drawnEdges collection
* @return return true if the drawnEdges collection contains direction; false otherwise
*/
public boolean hasEdge(Direction dir)
{
return drawnEdges.contains(dir);
}
/**
* Add a direction to the drawn edges collection
*
* @param dir
* the direction to be added to the drawnEdges collection
* @param player
* the current player and the owner of the box if the drawnEdges collection size is
* equal to four
*/
public void drawEdge(Direction dir, Player player)
{
drawnEdges.add(dir);
if (drawnEdges.size() == 4)
{
owner = player;
}
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.