Overview Details Your implementation must be named edu.vt.cs5044.DABPanel and yo
ID: 3717050 • Letter: O
Question
Overview
Details
Your implementation must be named edu.vt.cs5044.DABPanel and your JUnit test suite must be named edu.vt.cs5044.DABPanelTest. The system relies upon your own Project 4 DABGame implementation as the fundamental engine for this system.
Reference Implementation
It is fully recognized that some of you may have outstanding bugs and/or missing features in your Project 4 DABGame implementation. That's not any problem at all. Everyone is free to download a fully operational implementation of Project 4 (as a JAR with class files only; no source code) for integration within this project.
Graphical Interface Description
DABGrid
DABGrid is the custom component responsible for drawing the grid. You must integrate this component within your overall layout. By default, this component simply displays the current state of the grid, by calling DABGame accessor methods. When this component is set to interactive mode, the grid will become interactive, responding to mouse movements and clicks. Hovering the mouse near an un-drawn edge will highlight the edge. Clicking a highlighted edge will cause this component to call the DABGame drawEdge() mutator to draw the edge, then notify your system via a callback that the status indicators must be refreshed. Interactive mode must be activated and deactivated by your code, in response to your menu system.
Testing
Testing of GUI applications is notoriously complicated. Because the Swing system actually takes primary control of application, we can't just call the application code directly as in our previous systems. In order for test code to interact with the application, we first need to be sure that each component has a name assigned. The test code must search through the component hierarchy looking for these names, in order to fetch references to the key components. All of this is handled for you already in the starter code.
Once you have references to the Swing components, your test code needs to ask Swing to schedule your method calls. At that point you may query the state of the the GUI directly with accessors, and make assertions as normal.
This can all be done via standard JUnit test cases, but there a few additional issues that we won't have time to cover in detail. Thus a complete JUnit test suite is provided for download below. This is exactly the same test suite used by Web-CAT for this assignment. Assuming you don't have any redundant conditionals or other such problems in your code, this test suite should also achieve 100% coverage of your code.
Getting started with Eclipse
Configuring the Build Path
Create a new project in Eclipse and create the edu.vt.cs5044 package within the src folder, and another new source folder called test. Right-click the project and select Build Path | Configure Build Path, then select the Libraries tab.
First, click "Add Library" then select JUnit | JUnit 4 and click Finish.
Next, use "Add External JARs" to navigate to and select the dab5044.jar library you downloaded during Project 4 (available below). Expand the library node, select Javadocs, and click Edit to verify and add the dab5044-api.jar file (also available below) from Project 4 as the Javadocs.
Next, you need to download the dabgui.jar and dabgui-api.jar files (both available below) and repeat the process above to add them to your project libraries as well.
To use the reference implementation, just download the dabgame-ref.jar file below, and save it somewhere convenient.
Once you've completed at least one of the options above, or if you later just want to switch between the two options, right-click your Project 6 project, click Build Path | Configure Build Path, then select the Libaries tab. If you already have one of the implementations above listed in the libraries area, select it and cilck Remove. To add an implementation, use "Add External JARs" then navigate to the Jar file of your choice, select it, and click OK. You do not need to add Javadocs to this file.
Starter code and test code
Download the DABPanel.java and DABPanelTest.java files anywhere convenient. Open the folder in your operating system, then drag these files to the edu.vt.cs5044 package of the src and test source folders respectively. Be sure to select "Copy" when Eclipse asks how to import these files. If you configured the build path properly, both files should compile with no errors (although there are lots of Checkstyle issues with the starter code).
Please carefully review both the starter file and the test file before you begin. Note that you don't need to add to the test file, nor alter it in any way. The comments are there to help you understand how it works. The starter code is also commented to help guide your implementation approach. There's a "TODO" comment in each location where you must develop code.
Downloads
dabgui.jar - The DABGrid custom component, plus a utility class for component names
dabgui-api.jar - The API for the DABGrid component and utility class
dabgame-ref.jar - Reference implementation of the DotsAndBoxes interface
DABPanel.java - Starter code for your implementation
DABPanelTest.java - Complete JUnit test code for your implementation
DABPanel.java
package edu.vt.cs5044;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import static edu.vt.cs5044.DABGuiName.*;
public class DABPanel extends JPanel implements ActionListener {
private final DotsAndBoxes game;
private final JLabel p1ScoreLabel;
private final JLabel p2ScoreLabel;
private final JLabel turnLabel;
private final JComboBox<Integer> xCombo;
private final JComboBox<Integer> yCombo;
private final JComboBox<Direction> dirCombo;
private final JButton drawButton;
private final DABGrid dabGrid;
public DABPanel(JFrame frame) {
// add a menu bar to the frame that will contain this panel:
frame.setJMenuBar(setupMenuBar());
// create a new DotAndBoxes instance that will act as the game engine:
game = new DABGame();
// construct and name the user interface components; the names are needed for testing:
xCombo = new JComboBox<>();
xCombo.setName(X_COMBO);
yCombo = new JComboBox<>();
yCombo.setName(Y_COMBO);
dirCombo = new JComboBox<>(Direction.values());
dirCombo.setName(DIR_COMBO);
drawButton = new JButton();
drawButton.setName(DRAW_BUTTON);
drawButton.addActionListener(this);
drawButton.setText("Draw");
this.add(drawButton);
// TODO: use a method reference to add handleDrawButton() as a listener to the draw button
turnLabel = new JLabel();
turnLabel.setName(TURN_LABEL);
p1ScoreLabel = new JLabel();
p1ScoreLabel.setName(P1_SCORE_LABEL);
p2ScoreLabel = new JLabel();
p2ScoreLabel.setName(P2_SCORE_LABEL);
dabGrid = new DABGrid(game);
dabGrid.setName(DAB_GRID);
// layout all of the user interface components:
setupLayout();
// begin a new 3x3 game by default:
startGame(3);
}
private void handleDrawButton(ActionEvent ae) {
// TODO: the handler code for the draw button goes here
// TODO: don't forget to call updateStatus() if the draw was successful
}
private void updateStatus() {
// TODO: read the game status via accessors; set each label component's text accordingly
// TODO: don't forget to also disable the draw button if the game is over
// TODO: be sure to call repaint() at the end of this method
}
private void updateCombos() {
// TODO: update the coordinate combo box options, based on the current size of the grid
}
private void startGame(int size) {
// TODO: start a new game of the specified size, then call updateCombos() and updateStatus()
// TODO: don't forget to enable the draw button
}
private void setupLayout() {
// TODO: layout this panel and all its components; make sure it reasonably handles resizing
}
private JMenuBar setupMenuBar() {
JMenuItem menuItemNewGame2 = new JMenuItem();
menuItemNewGame2.addActionListener(e -> startGame(2));
// TODO: create the menu bar and populate it with the required items
// TODO: use lambda expressions so the new game items call startGame() when clicked
// TODO: use lambda expressions to handle activating and deactivating interactive mode
return null; // TODO: replace this placeholder to return the actual JMenuBar you created
}
private static void createAndShowGUI() {
// Boilerplate code; no changes required
JFrame frame = new JFrame("Dots And Boxes");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JComponent newContentPane = new DABPanel(frame);
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Boilerplate code; no changes required
// Note the use of a lambda expression to simplify this code
javax.swing.SwingUtilities.invokeLater(() -> {
DABPanel.createAndShowGUI();
});
}
/**
* {@inheritDoc}
*/
@Override
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
}
}
DABPanelTest.java
package edu.vt.cs5044;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import org.junit.After;
import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.*;
import static edu.vt.cs5044.DABGuiName.*;
//
// PLEASE NOTE: You don't need to alter this file in any way; please just use it as-is.
//
//CHECKSTYLE:OFF
@SuppressWarnings("javadoc")
public class DABPanelTest {
private JFrame dummyFrame;
private DABPanel dabPanel;
private DABGrid dabGrid;
private JComboBox<Integer> xCombo;
private JComboBox<Integer> yCombo;
private JComboBox<Direction> dirCombo;
private JLabel p1ScoreLabel;
private JLabel p2ScoreLabel;
private JLabel turnLabel;
private JButton drawButton;
private JMenuItem init2MenuItem;
private JMenuItem init3MenuItem;
private JMenuItem init4MenuItem;
private JMenuItem interactiveMenuItem;
//
// ----- PRIVATE HELPER METHODS -----
//
/**
* Ensure the score labels contain only the expected number, with no other digits.
*
* @param expectP1 expected score of Player.ONE
* @param expectP2 expected score of Player.TWO
*/
private void checkScores(int expectP1, int expectP2) {
assertTrue(p1ScoreLabel.getText().matches("[^\d]*" + expectP1 + "[^\d]*"));
assertTrue(p2ScoreLabel.getText().matches("[^\d]*" + expectP2 + "[^\d]*"));
}
/**
* Ensure the turn label contains only the correct player.
*
* @param expectPlayer expected current player
*/
private void checkTurn(Player expectPlayer) {
String turnString = turnLabel.getText();
assertTrue(turnString.contains(expectPlayer.toString()));
assertFalse(turnString.contains(expectPlayer.getOpponent().toString()));
}
/**
* Draw an edge by setting the combo boxes and simulating a click of the draw button.
*
* This must all be done within the context of Swing, so we must use a utility to ask Swing to
* schedule the task, then wait until it has been completed to continue testing.
*
* @param x coordinate x
* @param y coordinate y
* @param dir direction
*/
private void drawEdge(int x, int y, Direction dir) {
try {
SwingUtilities.invokeAndWait(() -> {
xCombo.setSelectedItem(x);
yCombo.setSelectedItem(y);
dirCombo.setSelectedItem(dir);
drawButton.doClick();
});
} catch (InterruptedException | InvocationTargetException e) {
throw new GameException("Swing invocation exception during testing");
}
}
/**
* Simulating a click of one of the menu items.
*
* This must all be done within the context of Swing, so we must use a utility to ask Swing to
* schedule the task, then wait until it has been completed to continue testing.
*
* @param item menu item to click
*/
private void clickMenuItem(JMenuItem item) {
try {
SwingUtilities.invokeAndWait(() -> item.doClick());
} catch (InterruptedException | InvocationTargetException e) {
throw new GameException("Swing invocation exception during testing");
}
}
/**
* Find a component by name within the hierarchy of Swing container.
*
* @param <T> Type of component expected to be returned, when it can be inferred by compiler
* @param root top-level container to search
* @param name name of component to find
* @return component with specified name, or null if no such component was found
*/
@SuppressWarnings("unchecked")
private <T extends Component> T findComponent(Container root, String name) {
for (Component child : root.getComponents()) {
if (name.equals(child.getName())) {
return (T) child;
}
if (child instanceof Container) {
T subChild = findComponent((Container) child, name);
if (subChild != null) {
return subChild;
}
}
}
return null;
}
//
// ----- TEST METHODS -----
//
/**
* Create a new frame and panel, then find all the relevant components by name.
*/
@Before
public void setUp() {
dummyFrame = new JFrame();
dabPanel = new DABPanel(dummyFrame);
dummyFrame.setContentPane(dabPanel);
xCombo = findComponent(dabPanel, X_COMBO);
yCombo = findComponent(dabPanel, Y_COMBO);
dirCombo = findComponent(dabPanel, DIR_COMBO);
drawButton = findComponent(dabPanel, DRAW_BUTTON);
p1ScoreLabel = findComponent(dabPanel, P1_SCORE_LABEL);
p2ScoreLabel = findComponent(dabPanel, P2_SCORE_LABEL);
turnLabel = findComponent(dabPanel, TURN_LABEL);
dabGrid = findComponent(dabPanel, DAB_GRID);
}
/**
* Explicitly dispose the frame after each test to release its resources.
*/
@After
public void tearDown() {
if (dummyFrame != null) {
dummyFrame.dispose();
}
}
@Test
public void testFoundAllComponents() {
assertNotNull(xCombo);
assertNotNull(yCombo);
assertNotNull(dirCombo);
assertNotNull(p1ScoreLabel);
assertNotNull(p2ScoreLabel);
assertNotNull(turnLabel);
assertNotNull(drawButton);
assertNotNull(dabGrid);
}
@Test
public void testInitialCombos() {
assertEquals(3, xCombo.getItemCount());
assertEquals(3, yCombo.getItemCount());
for (int i = 0; i < 3; i++) {
assertEquals(i, (int) xCombo.getItemAt(i));
assertEquals(i, (int) yCombo.getItemAt(i));
}
assertEquals(4, dirCombo.getItemCount());
for (Direction dir : Direction.values()) {
assertEquals(dir, dirCombo.getItemAt(dir.ordinal()));
}
}
@Test
public void testInitialLabels() {
assertTrue(p1ScoreLabel.getText().contains("ONE"));
assertTrue(p2ScoreLabel.getText().contains("TWO"));
checkScores(0, 0);
checkTurn(Player.ONE);
}
@Test
public void testInitialDrawEnabled() {
assertTrue(drawButton.isEnabled());
}
@Test
public void testMenuBarAndSetMenuFields() {
JMenuBar jmb = dummyFrame.getJMenuBar();
JMenu gameMenu = (JMenu) jmb.getComponent(0);
assertEquals("Game", gameMenu.getText());
assertEquals(2, gameMenu.getItemCount());
assertTrue(gameMenu.getItem(1) instanceof JCheckBoxMenuItem);
JMenuItem interactive = (JCheckBoxMenuItem) gameMenu.getItem(1);
assertTrue(interactive.getText().toLowerCase().contains("interact"));
interactiveMenuItem = interactive;
assertTrue(gameMenu.getItem(0) instanceof JMenu);
JMenu newGameMenu = (JMenu) gameMenu.getItem(0);
assertEquals("New", newGameMenu.getText());
assertEquals(3, newGameMenu.getItemCount());
init2MenuItem = newGameMenu.getItem(0);
init3MenuItem = newGameMenu.getItem(1);
init4MenuItem = newGameMenu.getItem(2);
assertTrue(init2MenuItem.getText().matches("[^\d]*2[^\d]*2?[^\d]*"));
assertTrue(init3MenuItem.getText().matches("[^\d]*3[^\d]*3?[^\d]*"));
assertTrue(init4MenuItem.getText().matches("[^\d]*4[^\d]*4?[^\d]*"));
}
@Test
public void testInitialInteractiveModeDisabled() {
testMenuBarAndSetMenuFields();
assertFalse(interactiveMenuItem.isSelected());
assertFalse(dabGrid.isInteractive());
}
@Test
public void testFirstMove() {
drawEdge(1, 1, Direction.TOP);
checkScores(0, 0);
checkTurn(Player.TWO);
}
@Test
public void testRedrawEdge() {
testFirstMove();
drawEdge(1, 1, Direction.TOP);
checkScores(0, 0);
checkTurn(Player.TWO);
}
@Test
public void testRedrawEdgeFromAdjacent() {
testFirstMove();
drawEdge(1, 0, Direction.BOTTOM);
checkScores(0, 0);
checkTurn(Player.TWO);
}
@Test
public void testInitAfterFirstMove() {
testFirstMove();
testMenuBarAndSetMenuFields();
clickMenuItem(init2MenuItem);
checkScores(0, 0);
checkTurn(Player.ONE);
}
@Test
public void testCompleteBox() {
testFirstMove();
drawEdge(1, 1, Direction.BOTTOM);
drawEdge(1, 1, Direction.RIGHT);
drawEdge(1, 1, Direction.LEFT);
checkScores(0, 1);
checkTurn(Player.TWO);
}
@Test
public void testInitAfterCompleteBox() {
testCompleteBox();
testMenuBarAndSetMenuFields();
clickMenuItem(init3MenuItem);
checkScores(0, 0);
checkTurn(Player.ONE);
assertTrue(drawButton.isEnabled());
}
@Test
public void testDrawAllHorizontalEdgesThenCompleteBox() {
drawEdge(0, 0, Direction.TOP);
drawEdge(1, 0, Direction.TOP);
drawEdge(2, 0, Direction.TOP);
drawEdge(0, 1, Direction.TOP);
drawEdge(1, 1, Direction.TOP);
drawEdge(2, 1, Direction.TOP);
drawEdge(0, 1, Direction.BOTTOM);
drawEdge(1, 1, Direction.BOTTOM);
drawEdge(2, 1, Direction.BOTTOM);
drawEdge(0, 2, Direction.BOTTOM);
drawEdge(1, 2, Direction.BOTTOM);
drawEdge(2, 2, Direction.BOTTOM);
drawEdge(0, 0, Direction.LEFT);
drawEdge(0, 0, Direction.RIGHT);
checkScores(0, 1);
checkTurn(Player.TWO);
}
@Test
public void testTwoBoxesTopRowAfterHorizontalEdges() {
testDrawAllHorizontalEdgesThenCompleteBox();
drawEdge(2, 0, Direction.RIGHT);
drawEdge(2, 0, Direction.LEFT);
checkScores(2, 1);
checkTurn(Player.ONE);
}
@Test
public void testTwoBoxesMiddleRowAfterHorizontalEdges() {
testTwoBoxesTopRowAfterHorizontalEdges();
drawEdge(1, 1, Direction.RIGHT);
drawEdge(1, 1, Direction.LEFT);
drawEdge(0, 1, Direction.LEFT);
checkScores(2, 3);
checkTurn(Player.TWO);
}
@Test
public void testTwoBoxesMiddleBottomRowAfterHorizontalEdges() {
testTwoBoxesMiddleRowAfterHorizontalEdges();
drawEdge(2, 2, Direction.LEFT);
drawEdge(2, 2, Direction.RIGHT);
drawEdge(2, 1, Direction.RIGHT);
checkScores(4, 3);
checkTurn(Player.ONE);
}
@Test
public void testCompleteGameAfterHorizontalEdges() {
testTwoBoxesMiddleBottomRowAfterHorizontalEdges();
drawEdge(0, 2, Direction.LEFT);
drawEdge(0, 2, Direction.RIGHT);
checkScores(4, 5);
String turnString = turnLabel.getText().toUpperCase();
assertTrue(turnString.contains("OVER"));
assertFalse(turnString.contains("ONE"));
assertFalse(turnString.contains("TWO"));
assertFalse(drawButton.isEnabled());
}
@Test
public void testInitAfterCompleteGame() {
testCompleteGameAfterHorizontalEdges();
testMenuBarAndSetMenuFields();
clickMenuItem(init4MenuItem);
checkScores(0, 0);
checkTurn(Player.ONE);
assertTrue(drawButton.isEnabled());
}
@Test
public void testEnableInteractiveMode() {
testInitialInteractiveModeDisabled();
clickMenuItem(interactiveMenuItem);
assertTrue(interactiveMenuItem.isSelected());
assertTrue(dabGrid.isInteractive());
}
@Test
public void testDisableInteractiveMode() {
testEnableInteractiveMode();
clickMenuItem(interactiveMenuItem);
assertFalse(interactiveMenuItem.isSelected());
assertFalse(dabGrid.isInteractive());
}
/**
* Invoke the application via DABPanel.main().
*
* NOTE: This method will very briefly display the entire interface at its normal size.
*
* ACADEMIC NOTE: This is only to achieve for 100% coverage; it serves no other useful purpose.
*/
@Test
public void testCallMain() {
DABPanel.main(new String[0]);
SwingUtilities.invokeLater(() -> {
for (Frame frame : Frame.getFrames()) {
frame.dispose();
}
});
}
}
Dots And Boxes? ? Game ? Player ONE Go! ?| Draw! ONE: 0 TWO: 0Explanation / Answer
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.*; public class swingfile_may2 extends JFrame,JPanel { public swingfile_may2() { this.setPreferredSize(new Dimension(400, 400)); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(EXIT_ON_CLOSE); } public void paint(Graphics g) { super.paint(g); int locX = 200; int locY = 200; g.drawLine(locX, locY, locX, locY); } public void PaintComponent (Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.blue); Dimension size = getSize(); Insets insets= getInsets(); int w = size.width - insets.left - insets.right; int h = size.height - insets.top - insets.bottom; Random r = new Random(); for (int i=0; iRelated Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.