I'm working on a guessing game where the object is where the player is given a board of 25 symbols and asked to try and guess the location of 6 hidden symbols. However, I've encountered two bugs whose cause I cannot identify.

  1. Regardless of whether the guess is a successful hit or not, the "miss" symbol is always displayed after the turn.

  2. In the inputReader class, there is a check for invalid input (something like 0g) which works fine. However, the next valid input (regardless of where it is inbounds or not) sets a symbol to the coordinates 0,0.

    public class Game
    {
        // suggested Game constants
        public static final String TARGET = "T ";          
        public static final String HIT = "* ";             
        public static final String MISS = "- ";           
        public static final int NUMBER_OF_TARGETS = 6; // number of targets hidden in the game grid
        public static final int NUMBER_OF_TRIES   = 10; // number of tries the user is given
    
        // suggested instance variables
        private Grid targetGrid;                       // the grid that holds the targets
        private Grid displayGrid;                      // the grid that displays hits and misses
        private InputReader reader;                    // input reader to get user coordinate choices
        private CoordinatePair coordinate;             // the coordinate pair that is to be tested.
    
        /**
         * Constructor for objects of class Game
         */
        public Game()
        {
            targetGrid = new Grid();
            displayGrid = new Grid();
            targetGrid.randomTargets();
            reader = new InputReader();
            coordinate = new CoordinatePair(); 
        }
    
        /**
         * Play the game - this method contains the game logic
         */
        public void playGame()
        {
            showInstructions();
            targetGrid.loadGrid();
            targetGrid.randomTargets();
            displayGrid.loadGrid();
            targetGrid.displayGrid();
            int guessAttempt = 1;
            while (guessAttempt <= NUMBER_OF_TRIES) {
                displayGrid.displayGrid();
                System.out.println("Try number " + guessAttempt);
                System.out.println("Coordinates start from zero");
                System.out.print("Type your choice of coordinates (row column) with a space in between");
                CoordinatePair input = reader.getCoordinates();
                int testRow = input.getRow();
                int testColumn = input.getColumn();
                while (testRow >= Grid.ROWS || testColumn >= Grid.COLUMNS) {
                    System.out.println("That is not a valid input. Please re-enter your intended input.");
                    input = reader.getCoordinates();
                    testRow = input.getRow();
                    testColumn = input.getColumn();
                }
                if (targetGrid.coordinate(testRow, testColumn).equals(TARGET)) {
                    displayGrid.setHit(testRow, testColumn);
                }
                else {
                    displayGrid.setMiss(testRow, testColumn);
                }
                guessAttempt++;
            }
        }
    
        /**
         * Provides instructions to the user
         */
        private void showInstructions()
        {
            System.out.println("Welcome to the Guessing Game. ");
            System.out.println("There are six targets hidden targets in the grid below. ");
            System.out.println("Type the coordinates of the grid location you want to try. ");
            System.out.println("An unsucessful attempt will show the symbol -" + ".\n" + "while a successful attempt will show the symbol *");
            System.out.println("You have ten attempts" + ".\n" + "Good Luck!");
        }
    }
    
    public class Grid
    {
        // suggested Grid constants
        public static final int ROWS = 5;           // number of rows
        public static final int COLUMNS = 5;        // number of columns
        public static final int NUMBER_OF_TARGETS = 6; // number of targets 
        public static final String HIDDEN = "$ ";   // default string to display
    
        // suggested Grid instance variables
        private String[][] grid;                // the grid itself, a 2-D array of String
        private Random random;                  // random number generator
    
        /**
         * The Grid constructor creates a new grid using public constants ROWS and COLUMNS. 
         * Constructor also creates a new random number generator. 
         */
        public Grid()
        {
            grid = new String[ROWS][COLUMNS];
            random = new Random();// initialize instance variables
        }
    
        /**
         * Loads the grid with the default symbol for a coordinate that has not been guessed.
         */
        public void loadGrid()
        {
            for (int counterRows = 0; counterRows < ROWS; counterRows++) {
                for (int counterColumns = 0; counterColumns < COLUMNS; counterColumns++) {
                    grid[counterRows][counterColumns] = HIDDEN;
                }
            }
        }
    
        /**
         * Loads the grid with targets in randomly chosen locations on the grid. The number of targets is equal to NUMBER_OF_TARGETS.
         */
        public void randomTargets()
        {
            for (int counter = 0; counter < NUMBER_OF_TARGETS; counter++) {
                int randomRow = random.nextInt(ROWS);
                int randomColumn = random.nextInt(COLUMNS);
                grid[randomRow][randomColumn] = Game.TARGET;
            }
        }
    
        /**
         * Creates a new 2D array of int to store a coordinate (row and column).
         * @param the chosen row coordinate.
         * @param the chosen column coordinate.
         */
        public int[][] coordinate(int row, int column)
        {
            int[][] coordinate = new int[row][column];
            return coordinate;
        }
    
        /**
         * Sets a "hit" symbol on the grid if a successful guess is made.
         * @param the chosen row coordinate.
         * @param the chosen column coordinate.
         */
        public void setHit(int row, int column)
        {
            grid[row][column] = Game.HIT;
        }
    
        /**
         * Sets a "miss" symbol on the grid if an unsuccessful guess is made.
         * @param the chosen row coordinate.
         * @param the chosen column coordinate.
         */
        public void setMiss(int row, int column)
        {
            grid[row][column] = Game.MISS;
        }
    
        /**
         * Prints out the grid and the symbols currently stored within. 
         */
        public void displayGrid()
        {
            for (int counterRow = 0; counterRow < grid.length; counterRow++) {
                for (int counterColumn = 0; counterColumn < grid[counterRow].length; counterColumn++) {
                    System.out.print (grid[counterRow][counterColumn] + " ");
                }
                System.out.println ();
            }
        }
    }
    
    public class CoordinatePair
    {
        private int row;
        private int column;
    
        /**
         * Constructor for objects of class CoordinatePair
         */
        public CoordinatePair()
        {
            row = 0;
            column = 0;
        }
    
        /**
         * @return the row coordinate of the pair.
         */
        public int getRow()
        {
            return row;
        }
    
        /**
         * @return the column coordinate of the pair.
         */
        public int getColumn()
        {
            return column;
        }
    
        /**
         * @param row to set.
         */
        public void setRow(int row)
        {
            this.row = row;
        }
    
        /**
         * @param column to set.
         */
        public void setColumn(int column)
        {
            this.column = column;
        }
    }
    
    public class InputReader
    {
        private Scanner scanner;
    
        /**
         * Create a new InputReader to read a coordinate pair.
         */
        public InputReader()
        {
            scanner = new Scanner(System.in);
        }
    
        /**
         * @return CoordinatePair with row and column typed by user, or null
         */
        public CoordinatePair getCoordinates()
        {
            CoordinatePair coords = new CoordinatePair();
            try {
                coords.setRow(scanner.nextInt());
                coords.setColumn(scanner.nextInt());    
            }
            catch(java.util.InputMismatchException exc) { // will catch non-numeric input
                scanner.nextLine();             // clear the buffer
                System.out.println("That is not a valid input. Please re-enter your intended input.");
                getCoordinates();
            }
            return coords;
        }        
    }
    

Line 239 after an error you re-call getCoordinates but you do NOT use the returned value at all.

Doesn't recalling the method cause it to restart? If so, wouldn't it take two more coordinates in the try section and provided they pass return those? Clearly I'm in the wrong here, but I'm just trying to understand.

It returns them, yes, but you don't assign the returned value to anything, so it's discarded. See the difference between these?

x = getCoordinates(); // runs method, assigns result to x
getCoordinates();     // runs method, dicards returned result

Ok of course that makes sense. Thanks! What about the hit and miss problem? That one existed before I implemented the invalid input check.

What controls the "miss" being shown?

The "miss" is shown if "hit" is determined to not have occured. I have already determined that the error likely lies in the way I've written the if statement for the hit, and it occurs to me as I'm typing this that the issue might be because coordinate() returns an array of int and I'm asking it to check if it equals a String. So therefore, I would have to write a method that returns the contents of the grid location and use that method instead. Am I on the right track here?

The "miss" is shown if "hit" is determined to not have occured.

Is that code working correctly? Add some printlns to show the values of all the variables used to make that decision to see what the computer sees.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.