Reputation: 722
I'm preparing application to play gomoku.
I've created nice looking GUI, now I'm fighting with core engine.
There is a class GameEngine
which has synchronized methods to make moves.
There are also classes implementing IClient
interface which are "players".
First thing to do is to implement PlayerClient
which is connected to the BoardPanel
and moves when MouseListener
inBoardPanel
(representing gomoku board) sais to. I want my application to be open to implement also computer players. That's why it's so complicated.
So... problem:
My GameEngine
class looks like this:
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();
}
}
}
and my Client class has run() method:
@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();
}
}
}
}
In place, where I wrote "//waitForPickedMove()" Client should wait for user to click proper place on the board. So... there is a MouseListener in my Board class:
private class MoveMouseListener implements MouseListener {
@Override
public synchronized void mouseReleased(MouseEvent e) {
if (gameState == null) {
return;
}
if (currentMove != null) {
movePicked();
repaint();
}
}
}
currentMove is of course move picked by user by clicking board. While movePicked() looks like this:
private synchronized void movePicked() {
if (gameState.isBlackToMove() && blackClient != null) {
blackClient.notify();
clearCurrentMove();
}
if (!gameState.isBlackToMove() && whiteClient != null) {
whiteClient.notify();
clearCurrentMove();
}
}
I tried to put wait()
in many places. I tried to reverse control and put it into Board
class, so it invoked methods in Client class (setCurrentMove(Move move)). Unfortunately I can't reach what I want. I always get IllegalMonitorStateException
or my GUI blocks.
I hope I explained my problem enough. I'd be thankful for any help.
EDIT:
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();
}
}
}
}
}
I'm pretty sure that I should synchronize sth, but I don't really know what.
EDIT 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();
}
}
}
}
Upvotes: 0
Views: 504
Reputation: 200148
There is no need for the Game Engine to constantly occupy a thread, blocking it when there's nothing to do. You should redesign this to be reactive: code executes when there is an event, in the thread where the event handler is executing. Then you won't need any wait
-notify
mechanisms.
If you want to allow a Player implementation to take its time without occupying the calling thread, design the API with asynchronicity in mind: IClient
will have a method representing "other player has moved", which will not return player's move immediately. The IClient
will be expected to call a method on the Game Engine with its move.
Upvotes: 4
Reputation: 31
Hi I would recommend you to you sleep() and notify(). If you want to stop some thread for unknown time give it sleep and when you need it again give it notify().
Upvotes: 0
Reputation: 1747
Hard to tell exactly what it is: a lot of pieces. But it looks like you should synchronize your notify call as described here:
http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify()
Upvotes: 0