Reputation: 1
There is a mysterious inversion happening when i disable buttons for users to press or not press. the project is to setup a battleship game and have one side be for a computer and the other for the user. When i have the so the user can press both buttons the ships show up properly on the buttons as hits. but when the computer shoots the buttons a mysteriously inverted 90 degrees south. here is the main part of the code and the AI class too
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
/**
* @author Alex Larson
* Project #3
* This is the main part of the BattleshipGUI.
* This class has several inner classes that are listeners.
* This class also has the main method in it.
* This class sets up the entire GUI.
*/
public class BsGui extends JFrame {
/**Array of FireButtons for the player */
FireButton play[][] = null;
/**Array of FireButtons for the player */
FireButton opp[][] = null;
/**A static constant for the player's BattleshipBoard */
public static BattleshipBoard playerB;
/**A static constant for the opponent's (or computer's) BattleshipBoard */
public static BattleshipBoard opponentB;
/**A static constant for a computer AI object */
public static ComputerAI AI;
/**A static constant that stores the computers designated AI */
public static char computer;
/**public int for passing around the shot the computer takes */
public int[][] compShot;
/**BorderLayout for the JFrame */
public BorderLayout br;
/**GridLayout for main JPanel */
public GridLayout gr;
/**GridLayout for both FireButton holding JPanels */
public GridLayout gr2;
/**GridLayout for bottom JPanel */
public GridLayout gr3;
/**FlowLayout: not used */
public FlowLayout fl;
/**JPanel that has the players FireButtons in it */
public JPanel playB;
/**JPanel that has the opponent's (or computer's) FireButtons in it */
public JPanel oppB;
/**JPanel that is not needed but hold the 2 FireButton holding JPanels */
public JPanel main;
/**JPanel that holds the title JLabel */
public JPanel top;
/**JPanel that hold shipsLeft button and ships JLabel */
public JPanel bottom;
/**Another not used, unneeded JPanel */
public JPanel left;
/**Another not used, unneeded JPanel */
public JPanel right;
/**JButton used to show user number of ships left */
public JButton shipsLeft;
/**JLabel used to show the title of the game */
public JLabel title;
/**JLabel used when game is over */
public JLabel win;
/**JLabel used to the user the number of ships left */
public JLabel ships;
/**Font used to change styles text */
public Font font = null;
/**
* Constructor for BsGui. It creates a GUI with JLabel as a center
* title and has 2 JPanels that hold arrays of FireButtons. It
* also sets up a button at the bottom that gives you the
* number of ships left for the players board, not the computers board.
*/
public BsGui(){
//Instantiating Section
play = new FireButton[10][10];
opp = new FireButton[10][10];
br = new BorderLayout(10,10);
gr = new GridLayout(1,2);
gr2 = new GridLayout(10,10);
gr3 = new GridLayout(2,2);
fl = new FlowLayout();
playB = new JPanel();
oppB = new JPanel();
main = new JPanel();
top = new JPanel();
bottom = new JPanel();
left = new JPanel();
right = new JPanel();
shipsLeft = new JButton();
title = new JLabel();
win = new JLabel();
ships = new JLabel();
font = new Font("Veranda", Font.BOLD, 20);
compShot = new int[2][1];
//Setting parameters for GUI
main.setBackground(Color.white);
main.setLayout(gr);
top.add(title);
playB.setBackground(Color.cyan);
playB.setName("Player Board");
playB.setLayout(gr2);
oppB.setBackground(Color.magenta);
oppB.setName("Computer Board");
oppB.setLayout(gr2);
shipsLeft.setText("How Many Ships Left");
shipsLeft.setVisible(true);
title.setText("Battleship");
title.setFont(font);
this.setTitle("Battlseship");
this.setSize(1100, 700);
this.setLayout(br);
//Adding Listeners
shipsLeft.addActionListener(new ShipsLeftListener());
//Adding components to GUI section
this.add(main, BorderLayout.CENTER);
this.add(top, BorderLayout.NORTH);
this.add(bottom, BorderLayout.SOUTH);
this.add(left, BorderLayout.WEST);
this.add(right, BorderLayout.EAST);
this.addFireBottonsToArray();
this.addFireButtonsPlay();
this.addFireButtonsOpp();
main.add(playB);
main.add(oppB);
bottom.add(shipsLeft);
bottom.add(ships);
}
/**
* This method adds new FireButtons to each part of the
* FireButton arrays. The first for loop adds buttons for the
* player. The second for loop adds buttons for the computer
* and makes them not click-able.
*/
private void addFireBottonsToArray(){
//Adds FireButtons to play array
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
play[j][i] = new FireButton(j, i);
}
}
//Adds FireButtons to opp array
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
opp[j][i] = new FireButton(j, i);
//opp[j][i].setEnabled(false);
}
}
}
/**
* This method adds and listener to each FireButton
* before adding it to the JPanel for the player.
*/
private void addFireButtonsPlay(){
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
play[j][i].addActionListener( new FireButtonListener());
playB.add(play[j][i]);
}
}
}
/**
* This method adds and listener to each FireButton
* before adding it to the JPanel for the computer.
*/
private void addFireButtonsOpp(){
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
opp[j][i].addActionListener( new OpponentButtonListener());
oppB.add(opp[j][i]);
}
}
}
/**
* This method hits buttons for the computer where ever
* the AI tells it to. Int x is the row of the button and
* int y is the column.
*
* @param int x
* The row coordinate.
* @param int y
* The column coordinate.
*/
public void computerButtonHitter(int x, int y){
if(opponentB.fireShot(x, y) == true){
opp[x][y].setBackground(Color.RED);
opp[x][y].setFont(font);
opp[x][y].setText("H");
}
else{
opp[x][y].setBackground(Color.BLUE);
opp[x][y].setFont(font);
opp[x][y].setText("M");
}
}
/**
* This inner class is for the FireButton Listener. This particular
* class does probably too much but it was an easy way to do the
* problem at hand.
*/
public class FireButtonListener implements ActionListener{
/**
* This method is mandatory with implementing ActionListener.
* When a FireButton is pressed it finds the place it was fired at
* and changes it to red if a ship exists at that spot and if
* not turns it blue. So red means hit and blue means miss. This
* method also adds an 'H' for hit and 'M' for miss to the button.
* This method then also calls the method to make the computer
* do its move based on a switch case for which AI to use.
*
* @param ActionEvent
* The event that triggers this method.
*/
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof FireButton){
FireButton fb = (FireButton)e.getSource();
//System.out.println("FireButton at "+(fb.getCell().getColumn()+1)+", "+(fb.getCell().getRow()+1)+" was pressed");
if(playerB.fireShot(fb.getCell().getColumn(), fb.getCell().getRow()) == true){
play[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.RED);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setText("H");
play[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
else{
play[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.BLUE);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setText("M");
play[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
switch(computer){
case 'r':
compShot = AI.randomShot();
computerButtonHitter(compShot[0][0], compShot[1][0]);
break;
case 's':
compShot = AI.systematicShot();
computerButtonHitter(compShot[0][0], compShot[1][0]);
break;
}
if(playerB.isGameOver() == true){
main.remove(playB);
main.remove(oppB);
font = new Font("Veranda", Font.BOLD, 50);
win.setFont(font);
win.setText("Congratulations u win!");
main.add(win);
}
if(opponentB.isGameOver() == true){
main.remove(playB);
main.remove(oppB);
font = new Font("Veranda", Font.BOLD, 50);
win.setFont(font);
win.setText("Awe too bad, the computer won");
main.add(win);
}
}
}
}
/**
* This Class is simple and offers the user a way finding how
* many ships he or she still needs to destroy.
*/
public class ShipsLeftListener implements ActionListener{
/**
* This method is mandatory when implementing ActionListener.
* It sets the JLabel ships to the number of ships left
* when the button is pressed.
*
* @param ActionEvent
* The event that triggers this method.
*/
public void actionPerformed(ActionEvent e){
ships.setText("" + playerB.getNumBattleshipsLeft());
}
}
/**
* This class works exactly as the first part of FireButtonListener.
* The only difference is it doesn't work now since all the
* opponent's (computer) buttons are disabled. This method is here
* for later use for 2 player mode. (Did not have time to get that far).
*/
public class OpponentButtonListener implements ActionListener{
/**
* This method is mandatory with implementing ActionListener.
* When a FireButton is pressed it finds the place it was fired at
* and changes it to red if a ship exists at that spot and if
* not turns it blue. So red means hit and blue means miss. This
* method also adds an 'H' for hit and 'M' for miss to the button.
*
* @param ActionEvent
* The event that triggers this method.
*/
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof FireButton){
FireButton fb = (FireButton)e.getSource();
//System.out.println("Opponent Button Pressed at "+(fb.getCell().getColumn()+1)+", "+(fb.getCell().getRow()+1)+" was pressed");
if(opponentB.fireShot(fb.getCell().getColumn(), fb.getCell().getRow()) == true){
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.RED);
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setText("H");
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
else{
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.BLUE);
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setText("M");
opp[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
}
}
}
/**
* Main Function
*
* The main runs everything as normal. :P
* It creates a GUI, an AI, and 2 BattleshipBoards.
*
* @param args
* Command line arguments
* For program to work correctly it
* requires the first arg to be a path to
* the player's ship placements. The second
* arg requires the same as the first but for the
* opponent. The 3rd arg requires a single letter
* that represents the chosen AI for the computer.
* The only supported letters at the moment are 'r' and 's'.
* 'r' is random and 's' is systematic. Other computer AIs and
* difficulties will be added later.
*/
public static void main(String[] args) {
String player;
String opponent;
String inputAI;
File fPlay;
File fOpp;
player = args[0];
opponent = args[1];
inputAI = args[2];
computer = inputAI.charAt(0);
AI = new ComputerAI(computer);
try{
fPlay = new File(player);
fOpp = new File(opponent);
playerB = new BattleshipBoard(fPlay);
opponentB = new BattleshipBoard(fOpp);
}
catch(FileNotFoundException fne){
System.out.println("File path given must be wrong or file doesnt exist");
System.exit(0);
}
catch(Exception e){
System.exit(0);
}
JFrame gui = new BsGui();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setVisible(true);
}
}
import java.util.Random;
/**
*
* @author Alex Larson XPS
*
*This class is how the computer gets its brains.
*Has a constructor to set up the computer and 2 brain methods.
*One method gives random shots and the other gives systematic shots.
*More brain options to be added later.
*/
public class ComputerAI {
/**This hold the last shot X coordinate */
public int lastShotX;
/**This hold the last shot Y coordinate */
public int lastShotY;
/**Not used, but will be for smarter AI
* will be for determining if last shot was a hit or not */
public boolean wasLastShotHit;
/**Not used, but will be for smarter AI,
* will be for holding last X hit */
public int lastHitX;
/**Not used, but will be for smarter AI,
* will be for holding last Y hit */
public int lastHitY;
/**Not used, but would be for keeping track of shots fired */
public int shotCounter;
/**Used for passing on the coordinates of the shot fired */
public int shotFired[][];
/**Used to keep track of all shots fired coordinates */
public int shotsFired[][];
/**The random number generator */
public Random gen;
/**Keeps track of the computer AI */
public char typeOfAI;
/**
* This is the computerAI constructor.
* It initializes all variables and
* gets the random generator ready to use.
*
* @param c
* This is the char that determines the type of AI to be used.
*/
public ComputerAI(char c){
lastShotX = -1;
lastShotY = -1;
wasLastShotHit = false;
lastHitX = -1;
lastHitY = -1;
shotCounter = 0;
//At 0,0 shotX will be stored and at 1,0 shotY will be stored
shotFired = new int[2][1];
//There are 100 total shots on a 10x10 board
//So this will hold 100 coordinates of shots
shotsFired = new int[100][2];
for(int i = 0; i < 100; i++){
int j = 0;
shotsFired[i][j] = -1;
shotsFired[i][j+1] = -1;
}
//Initializes the random number generator
gen = new Random(9);
typeOfAI = c;
}
/**
* Grabs the char representing the AI and returns it
*
* @return the type of AI being used
*/
public char getTypeOfAI(){
return typeOfAI;
}
/**
* This is the random shot brain.
* It uses a random number generator to makes random shots.
* It also keeps track of previous shots taken in shotsFired.
* After making sure the shot has been taken before it returns
* those coordinates.s
*
* @return the int[][] that represents the coordinates of the shot fired
*/
public int[][] randomShot(){
int hitX = gen.nextInt(9);
int hitY = gen.nextInt(9);
shotFired[0][0] = hitX;
shotFired[1][0] = hitY;
int i;
for(i = 0; i < 100; i++){
//This if statement is for setting that this shot has been taken
if(shotsFired[i][0] == -1){
shotsFired[i][0] = hitX;
shotsFired[i][1] = hitY;
break;
}
//This if statement is to make sure the shot being generated
//has not been taken yet.
if(shotsFired[i][0] == hitX && shotsFired[i][1] == hitY){
hitX = gen.nextInt(9);
hitY = gen.nextInt(9);
shotFired[0][0] = hitX;
shotFired[1][0] = hitY;
}
}
System.out.println(hitX +" "+ hitY);
return shotFired;
}
/**
* This is the systematic brain.
* It marches along row by row to fire shots.
* It keeps track of the last shot taken by using
* lastShotX and lastShotY. It then return the
* shot fired.
*
* @return the int[][] that represents the coordinates of the shot fired
*/
public int[][] systematicShot(){
if(lastShotX == -1 && lastShotY == -1){
lastShotX = 0;
lastShotY = 0;
shotFired[0][0] = lastShotX;
shotFired[1][0] = lastShotY;
return shotFired;
}
for(int i = 0; i < 10; i++){
if(lastShotX == -1){
lastShotX = 0;
shotFired[0][0] = lastShotX;
shotFired[1][0] = lastShotY;
return shotFired;
}
for(int j = 0; j < 10; j++){
if(lastShotX == j && lastShotY == i){
if(lastShotX == 9){
lastShotX = -1;
lastShotY++;
}
else{
lastShotX = j+1;
shotFired[0][0] = lastShotX;
shotFired[1][0] = lastShotY;
return shotFired;
}
}
}
}
return shotFired;
}
}
Upvotes: 0
Views: 207
Reputation: 39197
If you compare your method computerButtonHitter
if(opponentB.fireShot(x, y) == true){
opp[x][y].setBackground(Color.RED);
opp[x][y].setFont(font);
opp[x][y].setText("H");
}
else{
opp[x][y].setBackground(Color.BLUE);
opp[x][y].setFont(font);
opp[x][y].setText("M");
}
with the FireButtonListener
if(playerB.fireShot(fb.getCell().getColumn(), fb.getCell().getRow()) == true){
play[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.RED);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setText("H");
play[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
else{
play[fb.getCell().getRow()][fb.getCell().getColumn()].setBackground(Color.BLUE);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setFont(font);
play[fb.getCell().getRow()][fb.getCell().getColumn()].setText("M");
play[fb.getCell().getRow()][fb.getCell().getColumn()].setEnabled(false);
}
you'll find a difference. In short form the first has opponentB.fireShot(x,y)
together with opp[x][y]....
while the second has playerB.fireShot(c,r)
and play[r][c]....
so while the first has same order in method and array the second has not. I suppose you should swith one of those in order to remain consistent with each other. So either opp[y][x]
or play[c][r]
but I cannot judge which one is correct (because I do not have full code).
Upvotes: 1