我正准备申请玩gomoku。
我创建了漂亮的GUI,现在我正在与核心引擎作斗争。
有一个类GameEngine
,它具有同步方法来进行移动。
还有一些实现IClient
接口的类是“玩家”。
首先要做的是实现与PlayerClient
相关联的BoardPanel
,并在MouseListener
(代表gomoku board)sais中BoardPanel
时移动。我希望我的应用程序可以实现计算机播放器。这就是它如此复杂的原因。
所以......问题:
我的GameEngine
课程如下:
public class GameEngine {
private IClient blackPlayer;
private IClient whitePlayer;
private GameState gameState;
...
public void play() {
blackPlayer.run();
whitePlayer.run();
}
public synchronized void move(Move move) throws IllegalMoveException {
gameState.move(move);
if (move.isBlackMove()){
whitePlayer.notify();
}else{
blackPlayer.notify();
}
}
public synchronized void waitForYourTurn(boolean color){
try {
while (gameState.isBlackToMove()!=color) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我的Client类有run()方法:
@Override
public void run() {
while (gameState.getWinner() == 0) {
move = null;
boolean moved = false;
while (!moved) {
gameEngine.waitForYourTurn(black);
try {
//waitForPickedMove();
gameEngine.move(move);
moved = true;
} catch (IllegalMoveException e) {
e.printStackTrace();
}
}
}
}
在那里,我写了“// waitForPickedMove()”客户端应该等待用户点击板上的正确位置。所以...我的Board类中有一个MouseListener:
private class MoveMouseListener implements MouseListener {
@Override
public synchronized void mouseReleased(MouseEvent e) {
if (gameState == null) {
return;
}
if (currentMove != null) {
movePicked();
repaint();
}
}
}
currentMove当然是由用户通过点击棋盘来选择。虽然movePicked()看起来像这样:
private synchronized void movePicked() {
if (gameState.isBlackToMove() && blackClient != null) {
blackClient.notify();
clearCurrentMove();
}
if (!gameState.isBlackToMove() && whiteClient != null) {
whiteClient.notify();
clearCurrentMove();
}
}
我试图将wait()
放在很多地方。我试图反向控制并将其放入Board
类,因此它调用了Client类中的方法(setCurrentMove(Move move))。不幸的是,我无法达到我想要的。我总是得到IllegalMonitorStateException
或我的GUI块。
我希望我能充分解释我的问题。我会感谢任何帮助。
编辑:
public class MockComputerClient implements IClient {
private GameState gameState;
private GameEngine gameEngine;
private boolean black;
private ExecutorService executorService;
private boolean myTurn = false;
private int i = 3;
public MockComputerClient(GameEngine gameEngine, GameState gameState,
boolean black) {
this.gameEngine = gameEngine;
this.gameState = gameState;
this.black = black;
executorService = new ExecutorService();
executorService.run();
}
@Override
public void enemyMoved() {
myTurn = true;
executorService.notify();
}
private class ExecutorService implements Runnable {
@Override
public void run() {
while (gameState.getWinner() == 0) {
try {
while (!myTurn) {
wait();
}
// Hardcoded Moves
gameEngine.move(new Move(black, 3, i++));
myTurn = false;
} catch (InterruptedException | IllegalMoveException e) {
e.printStackTrace();
}
}
}
}
}
我很确定我应该同步,但我真的不知道是什么。
编辑2:
@Override
public void enemyMoved() {
myTurn = true;
executorService.move();
}
private class ExecutorService implements Runnable {
@Override
public void run() {
while (gameState.getWinner() == 0) {
System.out.println("Calculating: j= " + j);
if (j == 3)
j = 4;
else
j = 3;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void move() {
while (myTurn) {
try {
gameEngine.move(new Move(black, j, i++));
myTurn = false;
} catch (IllegalMoveException e) {
e.printStackTrace();
}
}
}
}
答案 0 :(得分:4)
游戏引擎不需要经常占用一个线程,当没有任何事情可以阻止它时。你应该重新设计它是被动的:代码在有事件时执行,在执行事件处理程序的线程中。那么您将不需要任何wait
- notify
机制。
如果你想让Player实现在不占用调用线程的情况下花费时间,请考虑异步性设计API:IClient
将有一个表示“其他玩家已移动”的方法,该方法不会返回球员立即行动。预计IClient
将在游戏引擎上调用一个方法。
答案 1 :(得分:0)
很难确切地知道它是什么:很多碎片。但看起来你应该同步你的通知电话,如下所述:
http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify()
答案 2 :(得分:0)
嗨我建议你睡觉()并通知()。如果你想在未知的时间停止一些线程让它睡觉,当你需要它时再给它notify()。