-1

I have a bingo game I am trying to code, I got hit with some logic problems and I am also looking for a way to tidy up the following code. (a Bingo game is won by crossing out the numbers in a straight line (diagonally straight line also counts.))

My current code for the 5x5 grid to check for straight "XX"s. Checks for all 5 straight rows and 2 diagonally straights.

    public static void bingoCheck(String[][] card1, String[][] card2) {
    
    //check for player 1 bingo.
    if ((card1[0][0] == "XX") && (card1[0][1] == "XX") && (card1[0][2] == "XX") && (card1[0][3] == "XX") && (card1[0][4] == "XX")) {
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[1][0] == "XX") && (card1[1][1] == "XX") && (card1[1][2] == "XX")  && (card1[1][3] == "XX") && (card1[1][4] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[2][0] == "XX") && (card1[2][1] == "XX") && (card1[2][2] == "XX")  && (card1[2][3] == "XX") && (card1[2][4] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[3][0] == "XX") && (card1[3][1] == "XX") && (card1[3][2] == "XX")  && (card1[3][3] == "XX") && (card1[3][4] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[4][0] == "XX") && (card1[4][1] == "XX") && (card1[4][2] == "XX")  && (card1[4][3] == "XX") && (card1[4][4] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[0][4] == "XX") && (card1[1][3] == "XX") && (card1[2][2] == "XX")  && (card1[3][1] == "XX") && (card1[4][0] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    } else if ((card1[4][4] == "XX") && (card1[3][3] == "XX") && (card1[2][2] == "XX")  && (card1[1][1] == "XX") && (card1[0][0] == "XX")){
        System.out.print("Bingo! Player 1 wins!");
    }
    // player 2 check 
    else if ((card2[0][0] == "XX") && (card2[0][1] == "XX") && (card2[0][2] == "XX")    && (card2[0][3] == "XX") && (card2[0][4] == "XX")) {
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[1][0] == "XX") && (card2[1][1] == "XX") && (card2[1][2] == "XX")  && (card2[1][3] == "XX") && (card2[1][4] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[2][0] == "XX") && (card2[2][1] == "XX") && (card2[2][2] == "XX")  && (card2[2][3] == "XX") && (card2[2][4] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[3][0] == "XX") && (card2[3][1] == "XX") && (card2[3][2] == "XX")  && (card2[3][3] == "XX") && (card2[3][4] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[4][0] == "XX") && (card2[4][1] == "XX") && (card2[4][2] == "XX")  && (card2[4][3] == "XX") && (card2[4][4] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[0][4] == "XX") && (card2[1][3] == "XX") && (card2[2][2] == "XX")  && (card2[3][1] == "XX") && (card2[4][0] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else if ((card2[4][4] == "XX") && (card2[3][3] == "XX") && (card2[2][2] == "XX")  && (card2[1][1] == "XX") && (card2[0][0] == "XX")){
        System.out.print("Bingo! Player 2 wins!");
    } else {
        //back to getting user input
        userIn(card1, card2);
    }   
}

The logic problem. I want to be able to announce 2 winners at the same time if both grids get the straight line.

This is how the output is right now, both cards got straight lines at the same time but the code only announces Player 2 as the winner only.

Player 1's card:
 24  XX   8   1  25 
 12  XX   7  17  15 
  5  XX  20  19  13 
 14  XX  XX   4   3 
 10  XX  11  21   9 

Player 2's card:
 24  21  17  15  XX 
 10   3   8  XX  20 
 14   7  XX  12   5 
 25  XX  13  19  11 
 XX   4   9   1  XX 
Bingo! Player 2 wins!

Expecting output :

Player 1's card:
 24  XX   8   1  25 
 12  XX   7  17  15 
  5  XX  20  19  13 
 14  XX  XX   4   3 
 10  XX  11  21   9 

Player 2's card:
 24  21  17  15  XX 
 10   3   8  XX  20 
 14   7  XX  12   5 
 25  XX  13  19  11 
 XX   4   9   1  XX 
Bingo! Player 1 wins!
Bingo! Player 2 wins!

If there is any way to tidy up/easier to write code then that'd be great too.

How to check for repeated numbers? If user already used a number then it should print out a message telling them that and then giving them back the input to type again. Here's my current code. public static void userIn(String[][] card1, String[][] card2) {

public static void userIn(String[][] card1, String[][] card2) {
String str = "";
        System.out.print("Game host call (0 to exit): ");
        choice = sc.nextInt();
        
        // for user to exit the game
        if (choice == 0) {
            System.exit(0);
        } else {
            
            //check for out of bounds numbers
            while (choice < 0 || choice > 25) {
                System.out.println("The number must be between 1 to 25, please call again!");
                System.out.print("Game host call (0 to exit): ");
                choice = sc.nextInt();
            } 
            
            //change user input to String
            str = Integer.toString(choice);
            
            //check if user input matches that on cards
            for (i = 0;i <=4; i++) {
                for (j = 0;j <=4; j++) {
                    if (str.equals(card1[i][j])) {
                        card1[i][j] = "XX";
                    } 
                    if (str.equals(card2[i][j])) { 
                        card2[i][j] = "XX";
                    } 
                } 
            } 
            
            //print player 1 card
            System.out.println(player1);
            for (i = 0; i < card1.length; i++) {
                for (j = 0; j < card1.length; j++) {
                    System.out.printf(" %2s ", card1[i][j]);
                }
                System.out.print("\n");
            }
            
            // line break
            System.out.print("\n");
            
            //print player 2 card
            System.out.println(player2);
            for (i = 0; i < card2.length; i++) {
                for (j = 0; j < card2.length; j++) {
                    System.out.printf(" %2s ", card2[i][j]);
                }
                System.out.print("\n");
            }
            
            // go to check if any player won.
            bingoCheck(card1, card2);
        }
    }
Anas
  • 23
  • 5
  • there is a way to tidy it up, use for loops. After that you could see the error in logic easily. – Albin Paul Nov 14 '21 at 15:15
  • You forgot to check for vertical lines. You have checked for horizontal and diagonal. For both to be display as winner, you'll have to check both player's grids seperately. Not as `if check player1; else check player2`. – sittsering Nov 14 '21 at 15:26
  • 1
    I would recommend breaking the code into multiple methods. Java is object oriented so create a class says MyCard. Then create method like isBingo() by passing in all the numbers that have been called out. Then create private methods like checkVertical() and checkHorizontal() etc. This way is it much easier to manage and debug. All these IF-ELSE-IF-ELSE is really do my head in :) – Minh Kieu Nov 14 '21 at 15:29
  • Do not use `==` to compare `String` instances, see https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java. In fact, compare any object only with `equals()` (unless you know what you are doing with `==` on objects). – Progman Nov 14 '21 at 18:21
  • 2
    @Progman No. "I got hit with some logic problems". – Peilonrayz Nov 14 '21 at 18:28

2 Answers2

2

This will do the job
Edited: For vertical checks & declaring 2 winners at once

public static void bingoCheck(String[][] card1, String[][] card2) {
        boolean player1 = checkWinner(card1); 
        boolean player2 = checkWinner(card2);
        if (player1) {
            System.out.println("Bingo! Player 1 wins!");
        }
        if (player2) {
            System.out.println("Bingo! Player 2 wins!");
        } 
        if (!(player1 || player2)) {
            userIn(card1, card2);
        }
    }
    
    private static boolean checkWinner(String[][] cards) {
        boolean isAllCrossed = true;
        int row = 0, col = 0;
        
        // check horizontals
        for (row = 0; row < cards.length; row++) {
            isAllCrossed = true;
            // check if whole row have XX
            for (col = 0; col < cards[0].length; col++) {
                if (!card[row][col].equals("XX")) {
                    isAllCrossed = false;
                    break;
                }
            }
            if (isAllCrossed) return true;
        }

        // check verticals
        for (col = 0; col < cards[0].length; col++) {
            isAllCrossed = true;
            // check if whole column have XX
            for (row = 0; row < cards.length; row++) {
                if (!card[row][col].equals("XX")) {
                    isAllCrossed = false;
                    break;
                }
            }
            if (isAllCrossed) return true;
        }
        
        // check digonal from top left to bottom right
        isAllCrossed = true;
        row = col = 0;
        while (row < cards.length) {
            if (!card[row][col].equals("XX")) {
                    isAllCrossed = false;
                    break;
                }
            }
            row++;
            col++;
        }
        if (isAllCrossed) return true;
        
        // check digonal from top right to bottom left
        isAllCrossed = true;
        row = 0;
        col = cards[0].length - 1;
        while (row < cards.length) {
            if (!card[row][col].equals("XX")) {
                isAllCrossed = false;
                break;
            }
            row++;
            col--;
        }
        
        return isAllCrossed;
    }
Ankit Kumar
  • 139
  • 8
  • does this also check for vertical XX's? I forgot to add that, sorry. Additionally, could I also know how I can store user's inputs to use in UserIn() so that if the number is already used, it will print out a message then give back user to input again. >I'd like to add the repeated number checks in userIn() method, I edited the post to include that problem at the bottom, thanks. – Anas Nov 15 '21 at 03:29
  • I'm getting about 2 errors now. ```java error: method checkWinner in class assignMain cannot be applied to given types; if (checkWinner(card1)) { ^ required: String[][],String[][] found: String[][] reason: actual and formal argument lists differ in length error: method checkWinner in class assignMain cannot be applied to given types; } else if (checkWinner(card2)) { ^ required: String[][],String[][] found: String[][] reason: actual and formal argument lists differ in length 2 errors ``` – Anas Nov 15 '21 at 04:11
  • @Anas Are you passing both player's card array in checkWinner() ? – Ankit Kumar Nov 15 '21 at 05:05
  • Yes I am. [Current code, I updated some of the cards into card1 which is one of the array, there is also card2](https://goonlinetools.com/snapshot/code/#m0yunk00xnhm522kih9i0l) – Anas Nov 15 '21 at 06:10
  • 1
    @Anas you have to pass only one player card at a time you can see the code I have presented as answer. As we are checking for winners one by one – Ankit Kumar Nov 15 '21 at 09:07
1

General rule in writing a code is that you should extract code that repeats into separate function and use it, instead of repeating its body many times.

In your case many things repeat.

  1. Notice that you have exactly the same code for checking each player's board. That's the first thing that you should extract to a separate method and just call it with board of each user.

  2. You are repeating logic for checking each row. You are also repeating code that's checks each column. You should extract two methods, i.e. checkRow and checkColumn and call it in the for loop for each row/column. Diagonal case can be handled as 3rd method.

  3. Checking all elements in one row/column should be done with a for loop, instead of manually checking each position individually.

Just to summarize: the core rule, that you should have applied here is: don't repeat yourself (DRY).

Mirek Pluta
  • 7,883
  • 1
  • 32
  • 23