Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

This assignment is meant to introduce you to design and implementation of except

ID: 3685645 • Letter: T

Question

This assignment is meant to introduce you to design and implementation of exceptions in an object-oriented language. It will also give you experience in testing an object-oriented support class. You will be designing and implementing a version of the game Nim. Specifically, you will design and implement a NimGame support class that stores all actual information about the state of the game, and detects and throws exceptions when problems occur. Basic Rules of Nim Most versions of the game Nim involves 3 rows of “sticks”. For example: | | | | | | | | | | | | | | | Players alternate turns, each removing between 1 and 3 sticks from some row of their choice. For example, if player 1 takes 3 sticks from row 2, the board will then look like: | | | | | | | | | | | | Of course, a player cannot take more sticks from a row than there are left. For example, a player cannot remove 3 sticks from row 2 of the above board. The game continues until some player is forced to take the last stick, leaving none on the board. That player loses. In your application, a human player will alternate moves with a “computer” player. To simplify things, the computer player will choose a random number of sticks (between 1 and 3) from a random row. Of course, the number of sticks removed must be legal. The NimGame Support Class Required Constructors and Methods Your NimGame support class is required to have the following constructors and methods: • public NimGame(int[] initialSticks) This constructor should create a new game with the initial number of sticks in each row set to the corresponding elements of initialSticks. For example, to create a game with initially 3, 5, and 7 sticks, this would be called as new NimGame(new int[]{3, 5, 7}); • public int getRow(int r) This inspector method returns the current number of sticks in row r. • public void play(int r, int s) This modifier method should remove s sticks from row r. It should also do validation on the number of sticks, throwing one of the following exceptions if the number of sticks, returning the following exceptions: o NoSuchRowException if the row is not between 1 and 3. o IllegalSticksException if the number of sticks taken is not between 1 and 3. o NotEnoughSticksException if the number of sticks taken is between 1 and 3, but more than the number of sticks remaining in that row. • public boolean isOver() This inspector returns true if there are no sticks left in any row, false otherwise. • public void AIMove() This modifier takes a random number of sticks (between 1 and 3) from a random row, in order to make the computer’s move. Note that this must also do validation, making sure that it does not take more sticks than there are left in a row. A simple way to do this is “generate and test”: while (not enough sticks in that row) { generate a random row and number of sticks } • public String toString() This should return the “state” of the object (that is, the number of sticks in each row) as a string. Note that it is not used in the visual application, but will be used for the JUnit testing described below. Important design note: Your NimGame methods will only throw exceptions. They will not be catching any exceptions. All exceptions will be caught within the actionPerformed method of the NimApp class. Designing Additional Exceptions The above situations are not the only in which an exception can occur. You are to look over your NimGame class methods and constructors and identify at least two other instances where it would be appropriate for an exception to be thrown. This is the main design exercise of this assignment. In each case, create an appropriate exception class, and modify the code to throw the exception if it occurs. The NimApp Application Class I have provided an application called NimApp for running your support class. When run (with a working NimApp class), it looks like the following: The player enters the row and sticks, and press the PLAYER button: The player then presses the COMPUTER button, which plays the computer’s random move: This continues until there are no more sticks, at which point whoever made the last move loses: This is done by repeatedly calling the play, AIMove, and isOver methods described above. Carefully examine the actionPerformed method in the application to see how this works, particularly with respect to now the play method is called: Handling NimApp Exceptions Note that there is currently no exception handling in this method. You are to modify this code to handle the three exceptions that may be thrown by the play method. In each case, it should pop up an approriate error message. For example: Also note that if the player makes an illegal move, it must remain their turn. Specifically, the code that enables the AIButton and disables the playButton must not be executed if an exception is thrown: Handling Other Exceptions Aside from the exceptions thrown by the play method, there is one other type of exception that might be thrown in this actionPerformed method due to player error. Add code to catch this exception and to display an appropriate messge. Hint: When you play the game, think about what “unusual” input a player could try to enter into the textfields. Creating JUnit Testing Cases Finally, you are to create a set of testing tools for your NimGame class using the JUnit testing tool. To start, right click the NimGame in NetBeans, and go to Tools Create JUnit Tests. This will set up a file called NimGameTest under the Test Packages folder. As shown in class, it will generate a test method for each of your methods. To simplify things, you are only required to create tests for the methods: • getRow • play You can comment out the rest of the tests if you like. Testing the getRow method Since this will be easier, I suggest that you start with this one. Your tester will need to do the following (some of which is already built in): • Construct an instance object of a NimGame. • Call your getRow method for some row to determine whether it returns the correct number of sticks in that row. Testing the play method You are to provide two tests for this method: • Taking a legal number of sticks from a legal row. • Taking sticks from an illegal row. Test case for legal play Since this is a modifier, you will need to make sure the state has changed correctly. More specifically: • Construct an instance object of a NimGame. • Call the play method, with a legal row and number of sticks. • Use your toString method to compare the expected state of the object to the actual state. Test case for illegal row Since your method will be expected to throw an exception if the player chooses an illegal row, the structure of these testing methods will be different: • Construct an instance object of a NimGame. • Inside a try block: o Call the play method for some illegal row. o Call fail (since we would have exited the block if an exception were thrown). • Inside the catch block: o Use your toString method to make sure the state of the game has not changed. Documentation Be sure to document the exception handling and testing components of your code. Specifically: • Document each method of your NimGame class, particularly the sections related to detecting and throwing exceptions. • Document the changes you make to the actionPerformed method related to handling the exceptions thrown by NimGame methods. • Document the two testing methods you create in JUnit, describing what they are testing and how.

My code:

NimApp class:

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package nimapp;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

/**

*

* @author jrsullins

*/

public class NimApp extends JFrame implements ActionListener {

private static final int ROWS = 3;

private JTextField[] gameFields; // Where sticks for each row shown

private JTextField rowField; // Where player enters row to select

private JTextField sticksField; // Where player enters sticks to take

private JButton playButton; // Pressed to take sticks

private JButton AIButton; // Pressed to make AI's move

  

private NimGame nim;

  

public NimApp() {

  

// Build the fields for the game play

rowField = new JTextField(5);

sticksField = new JTextField(5);

playButton = new JButton("PLAYER");

AIButton = new JButton("COMPUTER");

playButton.addActionListener(this);

AIButton.addActionListener(this);

AIButton.setEnabled(false);

  

// Create the layout

JPanel mainPanel = new JPanel(new BorderLayout());

getContentPane().add(mainPanel);

  

JPanel sticksPanel = new JPanel(new GridLayout(3, 1));

mainPanel.add(sticksPanel, BorderLayout.EAST);

  

JPanel playPanel = new JPanel(new GridLayout(3, 2));

mainPanel.add(playPanel, BorderLayout.CENTER);

  

// Add the fields to the play panel

playPanel.add(new JLabel("Row: ", JLabel.RIGHT));

playPanel.add(rowField);

playPanel.add(new JLabel("Sticks: ", JLabel.RIGHT));

playPanel.add(sticksField);

playPanel.add(playButton);

playPanel.add(AIButton);

  

// Build the array of textfields to display the sticks

gameFields = new JTextField[ROWS];

for (int i = 0; i < ROWS; i++) {

gameFields[i] = new JTextField(10);

gameFields[i].setEditable(false);

sticksPanel.add(gameFields[i]);

}

setSize(350, 150);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  

nim = new NimGame(new int[]{3, 5, 7});

draw();

}

  

// Utility function to redraw game

private void draw() {

for (int row = 0; row < ROWS; row++) {

String sticks = "";

for (int j = 0; j < nim.getRow(row); j++) {

sticks += "| ";

}

gameFields[row].setText(sticks);

}

rowField.setText("");

sticksField.setText("");

}

  

public void actionPerformed(ActionEvent e) {

  

// Player move

if (e.getSource() == playButton) {

  

// Get the row and number of sticks to take

int row = Integer.parseInt(rowField.getText())-1;

int sticks = Integer.parseInt(sticksField.getText());

  

// Play that move

nim.play(row, sticks);

  

// Redisplay the board and enable the AI button

draw();

playButton.setEnabled(false);

AIButton.setEnabled(true);

  

// Determine whether the game is over

if (nim.isOver()) {

JOptionPane.showMessageDialog(null, "You win!");

playButton.setEnabled(false);

}

}

  

// Computer move

if (e.getSource() == AIButton) {

  

// Determine computer move

nim.AIMove();

  

// Redraw board

draw();

AIButton.setEnabled(false);

playButton.setEnabled(true);

  

// Is the game over?

if (nim.isOver()) {

JOptionPane.showMessageDialog(null, "You win!");

playButton.setEnabled(false);

}

}

}

  

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

NimApp a = new NimApp();
NimGame b= new NimGame();
  
}

}

NimGame Class:

package nimapp;
import java.util.Random;
import javax.swing.JOptionPane;
import java.io.*;
import java.lang.*;

public class NimGame {
int x = 1;
int[] Sticks; //creating an array of sticks
int totalSticks = 0;

public NimGame(int[] initialSticks){
Sticks = initialSticks;}

public int getRow(int r){
return Sticks[r];}

public void play(int r, int s) throws NoSuchRowException, IllegalSticksException, NotEnoughSticksException
{
if (r < 0 || r > 2)
{
throw new NoSuchRowException();
}
if (s < 1 || s > 3)
{
throw new IllegalSticksException();
}
if (s > Sticks[r])
{
throw new NotEnoughSticksException();
}
  
Sticks[r] -= s;

  
// JOptionPane.showMessageDialog(null, "Too Many Sticks!");}
}
  
  
  
  
  
public boolean isOver(){
int theTotal = 0;
for (int i = 0; i< Sticks.length; i++){
theTotal = Sticks[i];
System.out.println(Sticks[i]);
System.out.println(theTotal);
}
totalSticks = theTotal;
if (totalSticks <= 0){
return true;
}
else return false;
}

public void AIMove(){
Random randomInt = new Random ();

boolean tryRemove = true;

while(tryRemove && totalSticks >= 1){
int RandomRow = randomInt.nextInt(3);
if(Sticks[RandomRow] <= 0)//the computer can't remove from this row
continue;

//the max number to remove from row
int size = 3;
if( Sticks[RandomRow] < 3)//this row have least that 3 cards
size = Sticks[RandomRow];//make the max number to remove from the row be the number of cards on the row
int RandomDiscard = randomInt.nextInt(size) + 1;
Sticks[RandomRow] = Sticks[RandomRow] - RandomDiscard;
//I don't know if this is needed, but since we remove a RandomDiscard amount lest decrease the totalSticks
totalSticks = totalSticks - RandomDiscard;
//exit loop
tryRemove = false;
}

if(totalSticks <= 1){
int RandomRow = 0;
Sticks[RandomRow] = Sticks[RandomRow]-1;
isOver();
}
}

}

And I have a class for each of the exceptions, as an example for the IllegalSticksException.

package nimapp;


import java.lang.*;
/**
*
*
*/
public class IllegalSticksException extends RuntimeException {

}



Please help! I'm really stuck. I can't figure out how to implement the exceptions and/or the toString methods. I haven't even been able to do the Junit testing yet.

Explanation / Answer

Answer:

Note: code has been implemented as per user requirements.

//IllegalSticksException.java
package nimapp;

import java.lang.*;
/**
*
*
*/
public class IllegalSticksException extends RuntimeException
{
   String s;
   public IllegalSticksException()
   {
       s="Illegal Sticks";
   }
   public String toString()
   {
       return s;
   }
}

//NoSuchRowException.java
package nimapp;

import java.lang.*;
/**
*
*
*/
public class NoSuchRowException extends RuntimeException
{
   String s;
   public NoSuchRowException()
   {
       s="Row doesn't exist";
   }
   public String toString()
   {
       return s;
   }
}


//NotEnoughSticksException.java
package nimapp;

import java.lang.*;
/**
*
*
*/
public class NotEnoughSticksException extends RuntimeException
{
   String s;
   public NotEnoughSticksException()
   {
       s="sticks are lesser";
   }
   public String toString()
   {
       return s;
   }
}