如何实现回电?

时间:2018-06-13 16:47:53

标签: java

如何在resetBoard()完成后使用回调来调用computerMove()?基本上我试图使用处理程序的延迟,但我的代码中有一个循环,我相信这是因为computerMove()在董事会重置时发生。

以下代码:

    @Override
                public void onClick(View v) {

                    if (!((Button) v).getText().toString().equals("")) {
                        return;
                    }

                    turnsCount++;

                    if (playerOneMove) {
                        ((Button) v).setText("X");
                        ((Button) v).setTextColor(playerX);
                        isGameOver();
                    }

                }

                public void isGameOver() {

                    if (checkGameIsWon()) {
                        if (playerOneMove) {
                            player1Wins();
                        } else {
                            player2Wins();
                        }
                    } else if (turnsCount == 9) {
                        draw();
                    } else {
                        playerOneMove = !playerOneMove;
                        if (!playerOneMove) {
                            final Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    computerMove();
                                }
                            }, random.nextInt(2000 - 1000 + 1000) + 1000);
                        }
                    }
                }

      private void computerMove() {
            String[][] field = new String[3][3];
            List<Button> emptyButtons = new ArrayList<>();

            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    field[i][j] = buttons[i][j].getText().toString();
                    if (field[i][j].equals("")) {
                        emptyButtons.add(buttons[i][j]);
                    }
                }
            }

    selectButton = emptyButtons.get(random.nextInt(emptyButtons.size()));

    selectButton.setText("O");
                    selectButton.setTextColor(playerO);
                    firstComputerMove = false;
                    turnsCount++;
                    isGameOver();

            }

                private void player1Wins() {
                    playerOnePoints++;
                    Toast.makeText(this, "Player 1 wins!", Toast.LENGTH_SHORT).show();
                    updatePointsText();
                    resetBoard();
                }

                private void resetBoard() {

                    final Handler handlerReset = new Handler();
                    handlerReset.postDelayed(new Runnable() {
                        @Override
                        public void run() {

                            for (int i = 0; i < 3; i++) {
                                for (int j = 0; j < 3; j++) {
                                    buttons[i][j].setText("");
                                }
                            }

                        }
                        },2000);
            } 

        private boolean checkGameIsWon() {
                String[][] field = new String[3][3];

                for (int i = 0; i < 3; i++) {
                    for (int j = 0; j < 3; j++) {
                        field[i][j] = buttons[i][j].getText().toString();
                    }
                }

                for (int i = 0; i < 3; i++) {
                    if (field[i][0].equals(field[i][1])
                            && field[i][0].equals(field[i][2])
                            && !field[i][0].equals("")) {
                        return true;
                    }
                }

                for (int i = 0; i < 3; i++) {
                    if (field[0][i].equals(field[1][i])
                            && field[0][i].equals(field[2][i])
                            && !field[0][i].equals("")) {
                        return true;
                    }
                }

                if (field[0][0].equals(field[1][1])
                        && field[0][0].equals(field[2][2])
                        && !field[0][0].equals("")) {
                    return true;
                }

                if (field[0][2].equals(field[1][1])
                        && field[0][2].equals(field[2][0])
                        && !field[0][2].equals("")) {
                    return true;
                }

                return false;
            }

            private void player1Wins() {
                playerOnePoints++;
                Toast.makeText(this, "Player 1 wins!", Toast.LENGTH_SHORT).show();
                updatePointsText();
                resetBoard();
            }

 private void player2Wins() {
            playerTwoPoints++;
            Toast.makeText(this, "Computer wins!", Toast.LENGTH_SHORT).show();
            updatePointsText();
            resetBoard();
            firstComputerMove = true;
            computerMove();
        }

        private void draw() {
            Toast.makeText(this, "Draw!", Toast.LENGTH_SHORT).show();
            resetBoard();
            playerOneMove = !playerOneMove;
            switchPlayerTurn();
            if (!playerOneMove){
                firstComputerMove = true;
                computerMove();
            }
        }

错误追踪:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.mima.tictactoe, PID: 10915
                  java.lang.IllegalArgumentException: n <= 0: 0
                      at java.util.Random.nextInt(Random.java:182)
                      at com.mima.tictactoe.MainActivityPlayer1.computerMove(MainActivityPlayer1.java:163)
                      at com.mima.tictactoe.MainActivityPlayer1.player2Wins(MainActivityPlayer1.java:340)
                      at com.mima.tictactoe.MainActivityPlayer1.isGameOver(MainActivityPlayer1.java:129)
                      at com.mima.tictactoe.MainActivityPlayer1.computerMove(MainActivityPlayer1.java:283)
                      at com.mima.tictactoe.MainActivityPlayer1.player2Wins(MainActivityPlayer1.java:340)
                      at com.mima.tictactoe.MainActivityPlayer1.isGameOver(MainActivityPlayer1.java:129)
                      at com.mima.tictactoe.MainActivityPlayer1.computerMove(MainActivityPlayer1.java:283)
                      at com.mima.tictactoe.MainActivityPlayer1.player2Wins(MainActivityPlayer1.java:340)
                      at com.mima.tictactoe.MainActivityPlayer1.isGameOver(MainActivityPlayer1.java:129)
                      at com.mima.tictactoe.MainActivityPlayer1.computerMove(MainActivityPlayer1.java:283)
                      at com.mima.tictactoe.MainActivityPlayer1.player2Wins(MainActivityPlayer1.java:340)
                      at com.mima.tictactoe.MainActivityPlayer1.isGameOver(MainActivityPlayer1.java:129)
                      at com.mima.tictactoe.MainActivityPlayer1.computerMove(MainActivityPlayer1.java:283)
                      at com.mima.tictactoe.MainActivityPlayer1.access$200(MainActivityPlayer1.java:20)
                      at com.mima.tictactoe.MainActivityPlayer1$3.run(MainActivityPlayer1.java:140)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:145)
                      at android.app.ActivityThread.main(ActivityThread.java:6934)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:372)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

1 个答案:

答案 0 :(得分:1)

三件事:

  1. 您正在Runnable方法中执行resetBoard(),该方法在与computerMove()方法不同的线程中运行该方法的内容;这就是为什么这两个方法同时运行的原因。你的resetBoard()逻辑是否需要在自己的线程内?你可以摆脱线程,让这个逻辑正常运行,这可以缓解你的问题,除非你某些你需要在这里使用一个单独的线程。
  2. 您看到的异常是在单独的线程上运行的computerMove()resetBoard()逻辑的副作用; java.lang.IllegalArgumentException: n <= 0: 0 at java.util.Random.nextInt(Random.java:182)被抛出是因为您在第182行传递0到随机数函数emptyButtons.get(random.nextInt(emptyButtons.size()));。条件if (field[i][j].equals(""))未通过,可能是因为您的resetBoard()方法没有在computerMove()被调用时已完成,因此field[i][j]的值尚未设置为""
  3. 格式化代码以摆脱与您的问题无关的任何逻辑,以及修复缩进将有助于其他人为您提供更好的解决方案。
  4. 或许更好的方法是在Thread方法中使用Runnable而不是resetBoard()。如果您确定要使用单独的线程,则可以使用waitnotify功能。 Check out how to use wait and notify with Threads here

    private Runnable resetBoard() {
        return new Thread() {
            @Override
            public void run() {
                synchronized(this){
                    for (int i = 0; i < 3; i++) {
                        for (int j = 0; j < 3; j++) {
                            buttons[i][j].setText("");
                        }
                    }
                    notify();
                }                
            }
        }
    }
    
    private void computerMove(Thread resetBoard) {
        resetBoard.start();
    
        synchronized(resetBoard){
            try{
                System.out.println("Resetting board...");
                resetBoard.wait();
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("Board is reset.");
    
            // ...
            // existing computerMove() logic here
            // ...
        }
    }
    
    public void draw() {
        Toast.makeText(this, "Draw!", Toast.LENGTH_SHORT).show();
        // resetBoard(); -- don't call here
        playerOneMove = !playerOneMove;
        switchPlayerTurn();
        if (!playerOneMove){
            firstComputerMove = true;
    
            // pass the result of resetBoard (new thread) here
            computerMove(resetBoard());
        }
    }
    

    为了将来参考,在执行其他逻辑之前,简单地尝试使用时间延迟来“等待”另一个线程的逻辑继续完成,这绝不是一个好主意。有很多原因可以解释为什么你永远不知道在完成之前需要花多长时间,因此你不应该只是“猜测”并使用类似2000毫秒(2秒)的东西。了解Threads如何在Java中工作,并了解为什么以及何时应该使用Thread生命周期钩子,例如waitnotify