Как повысить эффективность с помощью циклов for?

#java #arrays #if-statement #multidimensional-array

#java #массивы #if-оператор #многомерный массив

Вопрос:

Я начинающий Java-программист, и я создаю простую игру в крестики-нолики, используя 2D-массивы, и это мои инструкции if, чтобы проверить, выиграл ли игрок 1 или игрок 2. Я считаю, что это можно упростить, используя циклы for, однако я не понимаю, как использовать этот метод.

 if ((grid[0][0] == 1 amp;amp; grid[0][1] == 1 amp;amp; grid[0][2] == 1)
            || (grid[1][0] == 1 amp;amp; grid[1][1] == 1 amp;amp; grid[1][2] == 1)
            || (grid[2][0] == 1 amp;amp; grid[2][1] == 1 amp;amp; grid[2][2] == 1)
            || (grid[0][0] == 1 amp;amp; grid[1][1] == 1 amp;amp; grid[2][2] == 1)
            || (grid[0][2] == 1 amp;amp; grid[1][1] == 1 amp;amp; grid[2][0] == 1)
            || (grid[0][0] == 1 amp;amp; grid[1][0] == 1 amp;amp; grid[2][0] == 1)
            || (grid[0][1] == 1 amp;amp; grid[1][1] == 1 amp;amp; grid[2][1] == 1)
            || (grid[0][2] == 1 amp;amp; grid[1][2] == 1 amp;amp; grid[2][2] == 1)
            amp;amp; won == false) {
        title.setText("X wins!");
        won = true;
    } else if ((grid[0][0] == 2 amp;amp; grid[0][1] == 2 amp;amp; grid[0][2] == 2)
            || (grid[1][0] == 2 amp;amp; grid[1][1] == 2 amp;amp; grid[1][2] == 2)
            || (grid[2][0] == 2 amp;amp; grid[2][1] == 2 amp;amp; grid[2][2] == 2)
            || (grid[0][0] == 2 amp;amp; grid[1][1] == 2 amp;amp; grid[2][2] == 2)
            || (grid[0][2] == 2 amp;amp; grid[1][1] == 2 amp;amp; grid[2][0] == 2)
            || (grid[0][0] == 2 amp;amp; grid[1][0] == 2 amp;amp; grid[2][0] == 2)
            || (grid[0][1] == 2 amp;amp; grid[1][1] == 2 amp;amp; grid[2][1] == 2)
            || (grid[0][2] == 2 amp;amp; grid[1][2] == 2 amp;amp; grid[2][2] == 2)
            amp;amp; won == false) {
        title.setText("O wins!");
        won = true;
    }
  

Ниже приведен измененный код, который использует гораздо меньше выражений и условий if.

 public static boolean hasWon(int[][] grid) {
    for (int a = 1; a <= 2; a  ) {
        for (int b = 0; b < grid.length; b  ) {
            // Checking for win in horizontal, then vertical, then diagonal
            if (grid[b][0] == a amp;amp; grid[b][1] == a amp;amp; grid[b][2] == a) {
                won = true;
            } else if (grid[0][b] == a amp;amp; grid[1][b] == a amp;amp; grid[2][b] == a) {
                won = true;
            } else if ((grid[0][0] == a amp;amp; grid[1][1] == a amp;amp; grid[2][2] == a
                    || (grid[0][2] == a amp;amp; grid[1][1] == a amp;amp; grid[2][0] == a))) {
                won = true;
            }
        }
    }
}
  

Комментарии:

1. Не учтены все условия. И (true или false) проще, чем (1 или 2), я думаю.

2. Используйте два оператора for-loops и put if и else-if внутри внутреннего цикла.

3. Теперь код удовлетворяет всем условиям. Будет работать над решением цикла for для его очистки.

4. Что произойдет, если (строка 0 равна всем 1) и (строка 1 равна всем 2)?

5. Если строка 0 (верхняя строка) равна 1, выигрывает X, если строка 1 (средняя строка) равна 2, выигрывает O.

Ответ №1:

Чтобы помочь вам найти решение самостоятельно, я пока дам вам несколько советов.

Подсказка № 1: Подумайте о том, что значит побеждать. Игрок должен получить 3 своих жетона в ряд — по горизонтали, вертикали или диагонали. Подумайте о том, как это может быть представлено в вашей программе.

Подсказка № 2: Подумайте о том, как вы можете разбить проблему на более мелкие, более управляемые части. Подумайте о том, что общего у каждого выигрышного сценария, и разделите эту логику на метод, который вы можете вызывать несколько раз.

Подсказка № 3: Подумайте, что делает каждый выигрышный сценарий уникальным и как вы могли бы использовать свой grid для создания представления пространств, которые вы хотите изучить, которое легче проверить на выигрыш.

Если вы не уверены в том, как работают циклы for или другие аспекты языка Java, вы можете найти учебные пособия на сайте Oracle

Комментарии:

1. Спасибо, я отредактировал OP с моим новым решением, которое работает.

2. Рад быть полезным. Если вы хотите добавить дополнительный уровень сложности, просто чтобы еще немного напрячься, вы могли бы рассмотреть следующее: как бы вы написали свой код в общем виде, чтобы вы могли изменить доску на прямоугольник любого размера?

3. Установил бы я значение столбцов и строк для массива button и массива grid равным настраиваемому значению, объявленному вверху / в начале?

4. Да, именно так вы бы начали. Вам также потребуется изменить любую логику, которая зависит от наличия 3 строк и 3 столбцов, чтобы она была более универсальной.

5. Вам также нужно решить, как вы хотите обрабатывать диагонали, когда доска не квадратная. Для простоты вы могли бы просто решить, что собираетесь ввести правило, согласно которому допустимы только два из них — это действительно зависит от вас, поскольку прямоугольная доска полностью выходит за рамки обычных правил.

Ответ №2:

Да, вы правы. Циклы For — это правильный путь. Вот один из способов, которым вы могли бы это реализовать.

     public class tictactoe {

    public static void main(String[] args) {

        int[][] grid = {{1, 2, 1},
                {1, 2, 1},
                {2, 0, 1}};
        boolean won = hasWon(grid);


    }

    public static boolean hasWon(int[][] grid){
        for (int player = 1; player <= 2; player  ){
            boolean playerWon = false;
            for(int i = 0; i < 3; i  ){
                //Horizonal win
                playerWon = (grid[i][0] == player amp;amp; grid[i][1] == player amp;amp; grid[i][2] == player) || playerWon;

                //Vertical Win
                playerWon = (grid[0][i] == player amp;amp; grid[1][i] == player amp;amp; grid[i][2] == player) || playerWon;

            }
            //Diagonal Win
            playerWon = (grid[0][0] == player amp;amp; grid[1][1] == player amp;amp; grid[2][2] == player) || playerWon;
            playerWon = (grid[0][2] == player amp;amp; grid[1][1] == player amp;amp; grid[2][0] == player) || playerWon;

            if(playerWon){
                if(player == 1){
                    System.out.println("X wins!");
                    return true;
                }
                else{
                    System.out.println("O wins!");
                    return true;
                }
            }
        }
        //neither have won
        return false;
    }
}
  

Ответ №3:

Это не прямой ответ на вопрос. (поскольку это не стиль «проверять все сразу»)

Для упрощения
1. Проверьте, когда щелкается ячейка.
2. Условие зависит от места ячейки, на которую нажимается, и от того, кто щелкнул по ячейке.
3. Если кто-то выиграет, завершите игру.


пример кода

 // Part of codes.(not tested.)
// Each cell has three states (0, 1, or 2)

int player = 1; // (Not written here but) switch this each turn (1 or 2)

// In some place (activity.onCreate() etc)
{
    // For on click event(0, 0)
    cell_0_0.setOnClickListener(
        new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                grid[0][0] = player;
                final boolean isEnd = checkEnd_0_0();
                if (isEnd) {
                    // Call some function to end the game.
                    // Calling title.setText() in game end function maybe good.
                    // (as not needed to write many times.)
                    if (player == 1) {
                        title.setText("X wins!");
                    } else {
                        title.setText("O wins!");
                    }
                } else {
                    switchPlayer(); // Not written in this code.
                }
            }
        };
    );
    ...
}

// Call this on cell(0, 0) click event
// Returns true if someone wins.
boolean checkEnd_0_0() {
    // Omit checking grid[0][0] is 1 or 2 as it is clear.
    // Check horizontal.
    if (grid[0][1] == player) {
        if (grid[0][2] == player) {
            return true; // This is the case shown in question.
        }
    }
    // Check other cases (vertical, diagonal)
    ...
    // No match.
    return false;
}