I am working in the Treasure Hunt Game Project for my java class, I got super confused when the professor asked me to do this "Do not use instanceof, or break, except inside switch statements."
currently inside the functions i am using if and for statements.
Can i change it so i can get rid of intanceof?
In the button part I am using if(. . . intanceof. . . )
Can i do it with try and catch? instead of if? if so how?
Treasure Game
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class TreasureBoardPanel extends JPanel
{
private static final int WIDTH = 10;
private static final int HEIGHT = 10;
// Instance variables
private BoardButton[] button; //used to add the button to the panel
private TreasureGame game; //used to make make the constructor for the TreasureBoardPanel
//Costructor
public TreasureBoardPanel(TreasureGame game)
{
super();
this.game = game;
//setting the layout
setLayout(new GridLayout(WIDTH, HEIGHT));
//adding the buttons
addButtons();
}
//Create and adding buttons to panel
private void addButtons()
{
this.button = new BoardButton[WIDTH * HEIGHT];
//creating the random buttons
Random random = new Random();
for (int i = 0; i < TreasureGame.NUM_TREASURES; i++)
{
int index = random.nextInt(this.button.length);
//Check if index is already a button
while (this.button[index] != null)
index = random.nextInt(this.button.length);
this.button[index] = new TreasureButton();
}
// For all the buttons which are not TreasureButton i.e. null buttons
// create BoardButton
for (int i = 0; i < this.button.length; i++)
{
if (this.button[i] == null)
this.button[i] = new BoardButton();
}
// Add all buttons to the panel and add action listener
for (int i = 0; i < this.button.length; i++)
{
this.button[i].addActionListener(new ButtonListener(game));
add(this.button[i]);
}
}
//Display text from all treasures method
public void displayAllTreasures()
{
for (int i = 0; i < this.button.length; i++)
{
if (this.button[i] instanceof TreasureButton)
this.button[i].setText(this.button[i].getDisplayText());
}
}
}
The point your professor was making wasn't to replace if with switch, but to avoid using instanceof in the first place and use polymorphism instead. Usually you can just add a method to the object's class which either handles the task itself or returns the information needed for the task, and override it in subclasses.
In this case, you could add a method to BoardButton called isTreasure that returns false, and have TreasureButton override it to return true. Then you can just call btn.isTreasure() instead of checking which class it is.
Related
I'm trying to sum the similar threads inside the ExecutorService. I think I should use join() method, but I wasn't able to do it correctly.
My Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Gui extends JFrame implements ActionListener{
private JTextField txtSeats, txtAgents, txtTime;
public int numFirst, numSecond, numThird;
private JTextArea [] bookSeat;
private JButton btn1, btn2;
private String output, name;
private Random ran;
private JPanel p1, p2;
private String [] agentNumber;
private int [] sum;
private int x, z;
public Gui() {//A constructor for the Gui class.
ran = new Random();//Initializing the Random class.
setLayout(new BorderLayout());//Setting the layout for the JFrame.
setTitle("");//the title of the program.
p1 = new JPanel();//Creating the first JPanel to add JButtons and JTextField on it.
p1.setLayout(new FlowLayout());//Setting the first JPanel's layout.
//Creating 3 JTextField with a title for each, and adding each of them to the first JPanel.
txtSeats = new JTextField("Number of seats");
p1.add(txtSeats);
txtAgents = new JTextField("Number of agents");
p1.add(txtAgents);
txtTime = new JTextField("Max waiting time");
p1.add(txtTime);
//Creating 2 JButton with a title for each, and adding each of them to the first JPanel.
btn1 = new JButton("Create seats");
p1.add(btn1);
btn2 = new JButton("Book");
p1.add(btn2);
//Registering the 2 JButton to the ActionListener so they work with the actionPerformed() method when they get clicked.
btn1.addActionListener(this);
btn2.addActionListener(this);
add(p1, BorderLayout.NORTH);//Adding the first JPanel to the main JFrame at the position NORTH.
//Giving some properties to the JFrame layout.
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
}//End of the constructor.
public void createSeat() {//A method for creating a number of empty seats depending on the users wish.
//Storing the value of the first JTextField into an integer variable.
//With removing the spaces in it if there is any using "trim()".
numFirst = Integer.parseInt(txtSeats.getText().trim());
//Creating a JTextArea array for the number of seats the user wants to add.
//The size is entered by the user.
bookSeat = new JTextArea[numFirst];
p2 = new JPanel(); //Creating the second JPanel to add JTextArea on it.
p2.setLayout(new FlowLayout()); //Setting the second JPanel's layout.
//for-loop for adding the new JTextArea array into the second JPanel.
//With setting their title and background color and other properties.
for(int i = 0; i < numFirst; i++) {
bookSeat[i] = new JTextArea("Not booked");
bookSeat[i].setBackground(Color.WHITE);
bookSeat[i].setEditable(false);
p2.add(bookSeat[i]);
add(p2, BorderLayout.CENTER);//Adding the second JPanel to the main JFrame at the position CENTER.
setVisible(true);
}
}//End of createSeat() method.
#Override
public void actionPerformed(ActionEvent e) {//A method Overrode from the ActionListener interface.
if(e.getSource().equals(btn1)) {//First case: The JButton "Create seats" is clicked.
//Calling the createSeat() method; to create an empty seats based on the entered number of seats in the first JTextField.
createSeat();
//This method called on a container once new components are added or old ones removed.
//This call is an instruction to tell the layout manager to reset based on the new component list.
//revalidate() will trigger a call to repaint what the component thinks are 'dirty regions.'
//https://stackoverflow.com/questions/1097366/java-swing-revalidate-vs-repaint
revalidate();
}
else if(e.getSource().equals(btn2)) {//Second case: The JButton "Book" is clicked.
//Storing the values of the second and third JTextField into 2 integer variables.
//With removing the spaces in them if there is any using "trim()".
numSecond = Integer.parseInt(txtAgents.getText().trim());
numThird = Integer.parseInt(txtTime.getText().trim());
//Creating an ExecutorService object with fixed thread pool with maximum number of agents threads.
ExecutorService executor = Executors.newFixedThreadPool(numSecond);
//for-loop for the number of times the ExecutorService (thread pool) should run.
//It will keep creating threads until it reaches the maximum number of seats.
for(int i = 0; i < numFirst; i++) {
int count = i;
//Submitting Runnable task to the executor.
executor.execute(new Runnable() {
#Override
public void run() {//A method Overrode from the Runnable interface.
try {
//Getting the name of the current thread & store it in a String variable.
//Then we will have a long name like: pool-1-thread-n (n is a changing thread number).
//We use split("-"); to split it to 4 parts and we take the 4 part which is in position [3].
name = Thread.currentThread().getName();
agentNumber = name.split("-");
//Setting the new text and background color to the JTextArea array after they get booked.
bookSeat[count].setText("Booked by Agent " + agentNumber[3]);
bookSeat[count].setBackground(Color.RED);
revalidate();
//Generating random number between 0 and the waiting time entered by the user.
//And inserting this value inside the sleep() method. For a waiting time between each thread.
x = ran.nextInt(numThird + 1);
Thread.currentThread().sleep(x);
}
catch (Exception e) {}
}//End of run() method.
});//End of the executor.
}//End of the for-loop.
//Temporary solution for finding the similar elements in the array and return the sum for each
//equal threads. BUT NOT WORKING!!!
z = 0;
for(int i = 0; i < numFirst;i++) {
for(int j = 0; j < numFirst; j++) {
if(bookSeat[i].getName().equals(bookSeat[j].getName())) {
sum[i] = z + 1;
}
}
}
//for-loop for storing the booked seats in a String variable.
output = "";
for(int i = 1; i <= numSecond; i++) {
String allAgents = String.valueOf(i);
output += ("\n" + "Agent " + allAgents + " booked " + sum + " seats.");
}
//Displaying a Message Dialog with the information of each agent's booking.
JOptionPane.showMessageDialog(this,output);
//Shutdown the executor.
executor.shutdown();
//Wait until all tasks are finished.
while(!executor.isTerminated()) {
System.out.println("The booking has finished");
}
}//End of else if condition.
}//End of actionPerformed() method.
public static void main(String [] args) {//Main method.
new Gui(); //Calling the Gui.
}//End of Main method.
}//End of the class.
As you may see, I have tried with doing a nested for loop for checking the elements in the array if they were similar and return the sum of them. But this still didn't work!
z = 0;
for(int i = 0; i < numFirst;i++) {
for(int j = 0; j < numFirst; j++) {
if(bookSeat[i].getName().equals(bookSeat[j].getName())) {
sum[i] = z + 1;
}
}
}
Using Executor you loose direct access to the Thread instance which is needed for waiting for it (e.g. join()).
First create an array of Threads, then start them, then join() them. E.g.:
int numSecond = 3;
Runnable r = new Runnable() {
#Override
public void run()
{
// do your stuff inside thread
}//End of run() method.
};
IntStream.range(1,numSecond + 1).forEach( i -> {
Thread t = new Thread( r, "pool-1-thread-" + i);
t.start();
try
{
t.join();
}
catch ( InterruptedException t1 )
{
System.err.println( "thread interrupted" );
}
});
Above example names the thread as you expect in your code:
"pool-1-thread-" + i
If you are only interested in the numer then just pass in
"" + i
Using CompletableFutures might solve the problem also in an elegant way.
BTW1: Using a sleep(x) at the end of the thread's run method is absolutely senseless. It does not delay the start time of another thread. Why at all you want to do this? If you want to execute the logic in run() in a sequential way, there is no need to create use threads at all.
BTW2: Next time you asking something please boil down your code to a minimum which shows your problem. There is no need to setup a whole GUI with buttons, klick handlers etc.
BTW3: The access to shared (global) variables from inside the threads must be synchronized.
I am trying add an item listener to a checkbox to see if its been checked, and if it is, to be added to a list of SQL table names to be selected. Inversely, if it is not selected then remove it from the list. I cannot add a listener though to any checkbox because "they are not effitively final". What can I do/is there a better way to attack it?
My method:
public JPanel drawChecks(){
ArrayList<String> list = MainFrame.grabSQLTableNames();
int index = list.size();
int rows = 1;
while(index > 1){
rows++;
index = index - 3;
}
GridLayout c = new GridLayout(rows, 3);
JPanel panel = new JPanel(c);
JCheckBox check[] = new JCheckBox[list.size()];
for(int x = 0; x < list.size(); x++){
check[x] = new JCheckBox(list.get(x));
check[x].setVisible(true);
check[x].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (check[x].getState == true){
//do something
}
}
});
panel.add(check[x]);
}
Get the source of the event using the getSource method of the ItemEvent
public void itemStateChanged(ItemEvent e) {
JCheckBox checkBox = (JCheckBox)e.getSource();
if ( checkBox.isSelected() ){
//do something
}
}
For future reference, please read the following for tips on posting code examples for asking questions on stack overflow: https://stackoverflow.com/help/mcve
This is my first time using this site so don't go hard on me
I'm trying to make my own card game and in the game, the cards are placed in a 6 x 9 gridlayout. Everything else I can handle, but there is one feature in the game that I'm having trouble on, and if I can get it to work, I'll be finished. This is for my final project and it's due in about 5 days
I'm trying to make the cards shuffle when the user clicks on the White Joker card.
When that White Joker is clicked, the faced up cards and the other poker cards that are faced down are shuffled too. I don't want any duplicate cards in the grid
To be more explicit, I'll show my problem visually, because what I'm trying to do is complicated to explain in words and also complicated to make the code for it.
When the user clicks on one or more faced down cards, it'; look something like this:
When the White Joker is clicked it was shuffled and I don't want it to shuffle. I want everything else to shuffle while the White Joker stays in it's spot.
Here is my shuffle method code. Below I want this method to shuffle the JButtons but not the White Joker one. The White Joker one should stay
public JButton[] whiteJokerShuffle(JButton[] button)
{
//shuffles using fisher yates shuffle BUT ONLY White Joker does not
//shuffle
//FIX THISSSSSSSSSSSSSSSSSSSSSSS
Random rand = new Random();
int randomCard;
JButton randomValue;
for (int i = 0; i<button.length; i++)
{
randomCard = rand.nextInt(button.length);
//can't find a way to check for White Joker and make it stay
randomValue = button[randomCard];
button[randomCard] = button[i];
button[i] = randomValue;
}
return button;
}
And again, I do not want to see duplicate poker cards when I shuffle the cards and click on the buttons. I keep making that happen every time I try, and I don't know how to fix it so here is my other code that creates the frame and stuff:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
/**
*
* #author elngo
*/
public class GameFrame extends JFrame {
private final int FRAME_WIDTH = 900;
private final int FRAME_HEIGHT = 730;
private int _attempts = 0;
private GridLayout _buttonMatrix;
private ImageIcon _image;
private ImageIcon _faceDownImage;
private JButton[] _button;
private ActionListener _listener;
private JPanel _gridPanel;
private JOptionPane _introduction; //this pops up BEFORE the gamem starts
private JOptionPane _endGameResult; //this ONLY pops up when the game ENDS
//using the Cards class
private Cards _cards;
private String[] _pokerDeck;
private JButton _whiteJoker;
final int GRID_ROWS = 6;
final int GRID_COLUMNS = 9;
//Constructor
/**
*
*/
public GameFrame()
{
frameComponents();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
}
/**
*
*/
private void frameComponents()
{
_cards = new Cards(); //invokes Cards class
String[] faceDown = _cards.getFaceDown();
_pokerDeck = _cards.getPokerDeck();
//makes a matrix of JButtons
_button = new JButton[_pokerDeck.length];
_gridPanel = new JPanel(_buttonMatrix = new GridLayout(GRID_ROWS, GRID_COLUMNS));
_listener = new ClickListener();
//places FACE DOWN cards in the 6x9 grid first
for (int i = 0; i<faceDown.length; i++)
{
_faceDownImage = new ImageIcon(faceDown[i]);
_gridPanel.add(_button[i] = new JButton(_faceDownImage)); //adds to grid
_button[i].addActionListener(_listener);
}
add(_gridPanel);
//shuffle poker cards
//comment this randomizer out UNTIL I find a way to make WhiteJoker work
//_cards.shuffleDeck(_pokerDeck);
}
public class ClickListener implements ActionListener{
#Override
/**
*
*/
public void actionPerformed(ActionEvent event)
{
for (int i=0; i<_button.length; i++)
{
if (event.getSource() == _button[i])
{
_image = new ImageIcon(_pokerDeck[i]);
_button[i].setIcon(_image);
_attempts++;
System.out.println("Attempts: " + _attempts); //delete later
//***THE WHITE JOKER SHUFFLE PROBLEM STARTS HERE***
if (_pokerDeck[i] == "WJ.png") //if White Joker clicked
{
//FIX THISSSSSSSSSSSSSSSsssSSSSSSSSSssssSs
System.out.println("White Joker found"); //delete later
//save off Joker Spot so iterate through _buttonMatrix
String whiteJoker = _pokerDeck[i];
for (int j = 0; j<_button.length; j++)
{
if (_button[j] != null)
{
//***THE SHUFFLE METHOD I SHOWED IS USED BELOW***
_cards.whiteJokerShuffle(_button);
}
}
_gridPanel.removeAll();
for (JButton button : _button)
{
_gridPanel.add(button);
}
_gridPanel.revalidate();
_gridPanel.repaint();
}
//***PROBLEM STOPS HERE***
I really need help on this. Just this one complicated problem, and once it's solved, I'll tidy up my code and I'll be finished.
You can implement a modified version of the Fisher–Yates shuffle (or the modern version, designed for computer use, that was introduced by Richard Durstenfeld in 1964 and popularized by Donald E. Knuth):
When the White Joker is to be shuffled, you leave it on the same position.
When one of the other cards is to be shuffled, you make sure it is not swapped with the White Joker.
In the actionPerformed method, you iterate over all the buttons and then detect that the White Joker is clicked. The loop variable i contains the index of the White Joker, which you do not want to change. This value can be passed to the modified shuffle method.
To keep the example below short, I have passed an array of strings (instead of buttons) and determined the index of the White Joker inside the shuffle method:
import java.util.*;
public class GameFrame {
private static final String WHITE_JOKER_CODE = "*W";
public static void main(String[] arguments) {
String[] originalCards = {"5H", "5C", "6S", WHITE_JOKER_CODE, "7S", "KD"};
System.out.println("Original cards: " + Arrays.toString(originalCards));
String[] shuffledCards = new GameFrame().whiteJokerShuffle(originalCards);
System.out.println("Shuffled cards: " + Arrays.toString(shuffledCards));
}
// Uses the modern version of the Fisher–Yates shuffle, designed for computer use,
// as introduced by Richard Durstenfeld in 1964 and popularized by Donald E. Knuth.
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
public String[] whiteJokerShuffle(String[] cards)
{
int whiteJokerIndex = Arrays.asList(cards).indexOf(WHITE_JOKER_CODE);
Random randomNumbers = new Random();
for (int cardIndex = cards.length - 1; cardIndex > 0; cardIndex--)
{
if (cardIndex != whiteJokerIndex) {
// The upper bound is normally one higher than cardIndex, but it is
// lowered by one when the white joker is in the range (to "hide" it).
boolean hideJoker = cardIndex > whiteJokerIndex;
int upperBound = cardIndex + (hideJoker ? 0 : 1);
int swapIndex = randomNumbers.nextInt(upperBound);
if (swapIndex == whiteJokerIndex) {
swapIndex++;
}
// Swap the cards on indices swapIndex and cardIndex.
String swapCard = cards[swapIndex];
cards[swapIndex] = cards[cardIndex];
cards[cardIndex] = swapCard;
}
}
return cards;
}
}
The code below is supposed to create and object instance for a specific type (say color) JButton I want to represent in a grid. When I iterate through the for-loop to add the buttons to the jframe it adds nothing. But if I add a single instance variable it will add that. Anybody have an idea?
public class Grid {
protected JButton [][] board;
private JButton player;
private JButton openCell;
private JButton wall;
private JButton closedCell;
public Grid(String [] args) { // args unused
// Instantiation
board = new JButton [6][6];
layout = new String [6][6];
blueCell = new JButton("BLUE CELL");
redCell = new JButton("RED CELL");
greenCell = new JButton("GREEN CELL");
whiteCell = new JButton("WHITE CELL");
// Configuration (add actions later)
// Decoration
blueCell.setBackground(Color.blue);
redCell.setBackground(Color.red);
greenCell.setBackground(Color.green);
whiteCell.setBackground(Color.white);
for (int rows = 0; rows < 6; rows++) {
for (int cols = 0; cols < 6; cols++) {
if ((layout[rows][cols]).equals('*')) {
board[rows][cols] = blueCell;
}
else if ((layout[rows][cols]).equals('.')) {
board[rows][cols] = redCell;
}
else if ((layout[rows][cols]).equals('x')) {
board[rows][cols] = greenCell;
}
else {
board[rows][cols] = whiteCell;
}
}
}
JFrame game = new JFrame();
game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.setLayout(new GridLayout (6, 6));
game.setSize(500, 500);
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
if ((board[i][j]).equals(blueCell)) {
grid.add(blueCell);
}
else if ((board[i][j]).equals(redCell)) {
grid.add(redCell);
}
else if ((board[i][j]).equals(greenCell)) {
grid.add(greenCell);
}
else {
grid.add(whiteCell);
}
}
}
grid.setVisible(true);
} // end of constructor
} // end of Grid class
You can add a component to your GUI only once. If you add it to another component, it will be removed from the previous component. You're trying to add the same JButtons several times, and that won't work. Instead you're going to have to create more JButtons. Consider having your buttons share Actions which is allowed.
If you need more help, consider posting compilable code (your current code is not), a small runnable, compilable program that demonstrates your problem, in other words, an sscce.
Edit
You comment:
But don't these count as instances of a JButton not the same JButton? (I don't understand what your answer meant...)
Think of it mathematically... how many JButtons do you create in your code above? Well, this is easy to figure, exactly 4:
blueCell = new JButton("BLUE CELL");
redCell = new JButton("RED CELL");
greenCell = new JButton("GREEN CELL");
whiteCell = new JButton("WHITE CELL");
So, now ask yourself, how many JButtons are you trying to display in your GUI with these four JButtons? If it's four, then you're possibly OK (as long as you use each button), but if it's more, then you're in trouble. From your 6x6 grid, board = new JButton [6][6];, it looks like you're trying to display 36 JButtons, and if this is true, you've got problems.
But again, if still stuck, please consider creating and posting an sscce.
I need to make the following exceptions: NoSuchRowException if the row is not between 1 and 3, IllegalSticksException if the number of sticks taken is not between 1 and 3, and NotEnoughSticksException if the number of sticks taken is between 1 and 3, but more than the number of sticks remaining in that row. My issue is I really don't understand the syntax. If someone could help me get started with one exception, I think I can figure the others out.
So far I have the main 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();
}
}
The support 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 IllegalSticksException {
try {
Sticks[r]=Sticks[r]-s;
if(s < 0 || s > 3)
throw new IllegalSticksException();
} catch (IllegalSticksException ex){
JOptionPane.showMessageDialog(null, "Not a valid row!");
} catch (IndexOutOfBoundsException e){
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();
}
}
}
My issue is I really don't understand the syntax.
There is nothing wrong with the syntax as you have written it.
The problem is that you are catching the exception at the wrong place. You are (apparently) intending play to propagate the IllegalSticksException to its caller. But that won't happen because you are catching it within the play method.
There are two possible fixes depending on what you actually intent to happen.
You could remove the throws IllegalSticksException from the play signature.
You could remove the catch (IllegalSticksException ex){ ... } in play and catch/handle the exception at an outer level.