gpt4 book ai didi

java - 如何实现回调?

转载 作者:行者123 更新时间:2023-11-30 06:08:09 25 4
gpt4 key购买 nike

在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. 您正在执行Runnable在您的resetBoard()内方法,它在与 computerMove() 不同的线程中运行该方法的内容方法;这就是这两个方法同时运行的原因。你的resetBoard()吗?逻辑需要位于自己的线程内部吗?您可能可以摆脱该线程并让该逻辑正常运行,这将缓解您的问题,除非您确定需要在此处使用单独的线程。
  2. 您看到的异常是您的 computerMove()副作用resetBoard()逻辑在单独的线程上运行; java.lang.IllegalArgumentException: n <= 0: 0 at java.util.Random.nextInt(Random.java:182)被抛出是因为您将 0 传递给随机数函数 emptyButtons.get(random.nextInt(emptyButtons.size()));第 182 行。条件 if (field[i][j].equals(""))没有通过,可能是因为您的 resetBoard()该方法此时尚未完成 computerMove()被调用,所以值为 field[i][j]尚未设置为"" .
  3. 格式化您的代码以消除与您的问题无关的任何逻辑,并修复缩进将有助于其他人为您提供更好的解决方案。
<小时/>

也许更好的方法是使用 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 秒)之类的时间。了解线程在 Java 中的工作原理,并了解为什么以及何时应该使用线程生命周期 Hook ,例如 waitnotify .

关于java - 如何实现回调?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50842406/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com